1# This Source Code Form is subject to the terms of the Mozilla Public
2# License, v. 2.0. If a copy of the MPL was not distributed with this
3# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5# Common codegen classes.
6
7from collections import defaultdict
8from itertools import groupby
9
10import operator
11import os
12import re
13import string
14import textwrap
15import functools
16
17from WebIDL import (
18    BuiltinTypes,
19    IDLBuiltinType,
20    IDLInterfaceMember,
21    IDLNullableType,
22    IDLNullValue,
23    IDLObject,
24    IDLPromiseType,
25    IDLType,
26    IDLUndefinedValue,
27    IDLWrapperType,
28)
29
30from Configuration import (
31    MakeNativeName,
32    MemberIsUnforgeable,
33    getModuleFromObject,
34    getTypesFromCallback,
35    getTypesFromDescriptor,
36    getTypesFromDictionary,
37    iteratorNativeType
38)
39
40AUTOGENERATED_WARNING_COMMENT = \
41    "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
42FINALIZE_HOOK_NAME = '_finalize'
43TRACE_HOOK_NAME = '_trace'
44CONSTRUCT_HOOK_NAME = '_constructor'
45HASINSTANCE_HOOK_NAME = '_hasInstance'
46
47RUST_KEYWORDS = {"abstract", "alignof", "as", "become", "box", "break", "const", "continue",
48                 "else", "enum", "extern", "false", "final", "fn", "for", "if", "impl", "in",
49                 "let", "loop", "macro", "match", "mod", "move", "mut", "offsetof", "override",
50                 "priv", "proc", "pub", "pure", "ref", "return", "static", "self", "sizeof",
51                 "struct", "super", "true", "trait", "type", "typeof", "unsafe", "unsized",
52                 "use", "virtual", "where", "while", "yield"}
53
54
55def replaceFileIfChanged(filename, newContents):
56    """
57    Read a copy of the old file, so that we don't touch it if it hasn't changed.
58    Returns True if the file was updated, false otherwise.
59    """
60    # XXXjdm This doesn't play well with make right now.
61    #       Force the file to always be updated, or else changing CodegenRust.py
62    #       will cause many autogenerated bindings to be regenerated perpetually
63    #       until the result is actually different.
64
65    # oldFileContents = ""
66    # try:
67    #     with open(filename, 'rb') as oldFile:
68    #         oldFileContents = ''.join(oldFile.readlines())
69    # except:
70    #     pass
71
72    # if newContents == oldFileContents:
73    #     return False
74
75    with open(filename, 'wb') as f:
76        f.write(newContents)
77
78    return True
79
80
81def toStringBool(arg):
82    return str(not not arg).lower()
83
84
85def toBindingNamespace(arg):
86    return re.sub("((_workers)?$)", "Binding\\1", MakeNativeName(arg))
87
88
89def stripTrailingWhitespace(text):
90    tail = '\n' if text.endswith('\n') else ''
91    lines = text.splitlines()
92    for i in range(len(lines)):
93        lines[i] = lines[i].rstrip()
94    return '\n'.join(lines) + tail
95
96
97def innerContainerType(type):
98    assert type.isSequence() or type.isRecord()
99    return type.inner.inner if type.nullable() else type.inner
100
101
102def wrapInNativeContainerType(type, inner):
103    if type.isSequence():
104        containerType = "Vec"
105    elif type.isRecord():
106        containerType = "MozMap"
107    else:
108        raise TypeError("Unexpected container type %s", type)
109
110    return CGWrapper(inner, pre=containerType + "<", post=">")
111
112
113builtinNames = {
114    IDLType.Tags.bool: 'bool',
115    IDLType.Tags.int8: 'i8',
116    IDLType.Tags.int16: 'i16',
117    IDLType.Tags.int32: 'i32',
118    IDLType.Tags.int64: 'i64',
119    IDLType.Tags.uint8: 'u8',
120    IDLType.Tags.uint16: 'u16',
121    IDLType.Tags.uint32: 'u32',
122    IDLType.Tags.uint64: 'u64',
123    IDLType.Tags.unrestricted_float: 'f32',
124    IDLType.Tags.float: 'Finite<f32>',
125    IDLType.Tags.unrestricted_double: 'f64',
126    IDLType.Tags.double: 'Finite<f64>'
127}
128
129numericTags = [
130    IDLType.Tags.int8, IDLType.Tags.uint8,
131    IDLType.Tags.int16, IDLType.Tags.uint16,
132    IDLType.Tags.int32, IDLType.Tags.uint32,
133    IDLType.Tags.int64, IDLType.Tags.uint64,
134    IDLType.Tags.unrestricted_float,
135    IDLType.Tags.unrestricted_double
136]
137
138
139# We'll want to insert the indent at the beginnings of lines, but we
140# don't want to indent empty lines.  So only indent lines that have a
141# non-newline character on them.
142lineStartDetector = re.compile("^(?=[^\n#])", re.MULTILINE)
143
144
145def indent(s, indentLevel=2):
146    """
147    Indent C++ code.
148
149    Weird secret feature: this doesn't indent lines that start with # (such as
150    #include lines or #ifdef/#endif).
151    """
152    if s == "":
153        return s
154    return re.sub(lineStartDetector, indentLevel * " ", s)
155
156
157# dedent() and fill() are often called on the same string multiple
158# times.  We want to memoize their return values so we don't keep
159# recomputing them all the time.
160def memoize(fn):
161    """
162    Decorator to memoize a function of one argument.  The cache just
163    grows without bound.
164    """
165    cache = {}
166
167    @functools.wraps(fn)
168    def wrapper(arg):
169        retval = cache.get(arg)
170        if retval is None:
171            retval = cache[arg] = fn(arg)
172        return retval
173    return wrapper
174
175
176@memoize
177def dedent(s):
178    """
179    Remove all leading whitespace from s, and remove a blank line
180    at the beginning.
181    """
182    if s.startswith('\n'):
183        s = s[1:]
184    return textwrap.dedent(s)
185
186
187# This works by transforming the fill()-template to an equivalent
188# string.Template.
189fill_multiline_substitution_re = re.compile(r"( *)\$\*{(\w+)}(\n)?")
190
191
192@memoize
193def compile_fill_template(template):
194    """
195    Helper function for fill().  Given the template string passed to fill(),
196    do the reusable part of template processing and return a pair (t,
197    argModList) that can be used every time fill() is called with that
198    template argument.
199
200    argsModList is list of tuples that represent modifications to be
201    made to args.  Each modification has, in order: i) the arg name,
202    ii) the modified name, iii) the indent depth.
203    """
204    t = dedent(template)
205    assert t.endswith("\n") or "\n" not in t
206    argModList = []
207
208    def replace(match):
209        """
210        Replaces a line like '  $*{xyz}\n' with '${xyz_n}',
211        where n is the indent depth, and add a corresponding entry to
212        argModList.
213
214        Note that this needs to close over argModList, so it has to be
215        defined inside compile_fill_template().
216        """
217        indentation, name, nl = match.groups()
218        depth = len(indentation)
219
220        # Check that $*{xyz} appears by itself on a line.
221        prev = match.string[:match.start()]
222        if (prev and not prev.endswith("\n")) or nl is None:
223            raise ValueError("Invalid fill() template: $*{%s} must appear by itself on a line" % name)
224
225        # Now replace this whole line of template with the indented equivalent.
226        modified_name = name + "_" + str(depth)
227        argModList.append((name, modified_name, depth))
228        return "${" + modified_name + "}"
229
230    t = re.sub(fill_multiline_substitution_re, replace, t)
231    return (string.Template(t), argModList)
232
233
234def fill(template, **args):
235    """
236    Convenience function for filling in a multiline template.
237
238    `fill(template, name1=v1, name2=v2)` is a lot like
239    `string.Template(template).substitute({"name1": v1, "name2": v2})`.
240
241    However, it's shorter, and has a few nice features:
242
243      * If `template` is indented, fill() automatically dedents it!
244        This makes code using fill() with Python's multiline strings
245        much nicer to look at.
246
247      * If `template` starts with a blank line, fill() strips it off.
248        (Again, convenient with multiline strings.)
249
250      * fill() recognizes a special kind of substitution
251        of the form `$*{name}`.
252
253        Use this to paste in, and automatically indent, multiple lines.
254        (Mnemonic: The `*` is for "multiple lines").
255
256        A `$*` substitution must appear by itself on a line, with optional
257        preceding indentation (spaces only). The whole line is replaced by the
258        corresponding keyword argument, indented appropriately.  If the
259        argument is an empty string, no output is generated, not even a blank
260        line.
261    """
262
263    t, argModList = compile_fill_template(template)
264    # Now apply argModList to args
265    for (name, modified_name, depth) in argModList:
266        if not (args[name] == "" or args[name].endswith("\n")):
267            raise ValueError("Argument %s with value %r is missing a newline" % (name, args[name]))
268        args[modified_name] = indent(args[name], depth)
269
270    return t.substitute(args)
271
272
273class CGThing():
274    """
275    Abstract base class for things that spit out code.
276    """
277    def __init__(self):
278        pass  # Nothing for now
279
280    def define(self):
281        """Produce code for a Rust file."""
282        raise NotImplementedError  # Override me!
283
284
285class CGMethodCall(CGThing):
286    """
287    A class to generate selection of a method signature from a set of
288    signatures and generation of a call to that signature.
289    """
290    def __init__(self, argsPre, nativeMethodName, static, descriptor, method):
291        CGThing.__init__(self)
292
293        methodName = '\\"%s.%s\\"' % (descriptor.interface.identifier.name, method.identifier.name)
294
295        def requiredArgCount(signature):
296            arguments = signature[1]
297            if len(arguments) == 0:
298                return 0
299            requiredArgs = len(arguments)
300            while requiredArgs and arguments[requiredArgs - 1].optional:
301                requiredArgs -= 1
302            return requiredArgs
303
304        signatures = method.signatures()
305
306        def getPerSignatureCall(signature, argConversionStartsAt=0):
307            signatureIndex = signatures.index(signature)
308            return CGPerSignatureCall(signature[0], argsPre, signature[1],
309                                      nativeMethodName + '_' * signatureIndex,
310                                      static, descriptor,
311                                      method, argConversionStartsAt)
312
313        if len(signatures) == 1:
314            # Special case: we can just do a per-signature method call
315            # here for our one signature and not worry about switching
316            # on anything.
317            signature = signatures[0]
318            self.cgRoot = CGList([getPerSignatureCall(signature)])
319            requiredArgs = requiredArgCount(signature)
320
321            if requiredArgs > 0:
322                code = (
323                    "if argc < %d {\n"
324                    "    throw_type_error(cx, \"Not enough arguments to %s.\");\n"
325                    "    return false;\n"
326                    "}" % (requiredArgs, methodName))
327                self.cgRoot.prepend(
328                    CGWrapper(CGGeneric(code), pre="\n", post="\n"))
329
330            return
331
332        # Need to find the right overload
333        maxArgCount = method.maxArgCount
334        allowedArgCounts = method.allowedArgCounts
335
336        argCountCases = []
337        for argCount in allowedArgCounts:
338            possibleSignatures = method.signaturesForArgCount(argCount)
339            if len(possibleSignatures) == 1:
340                # easy case!
341                signature = possibleSignatures[0]
342                argCountCases.append(CGCase(str(argCount), getPerSignatureCall(signature)))
343                continue
344
345            distinguishingIndex = method.distinguishingIndexForArgCount(argCount)
346
347            # We can't handle unions at the distinguishing index.
348            for (returnType, args) in possibleSignatures:
349                if args[distinguishingIndex].type.isUnion():
350                    raise TypeError("No support for unions as distinguishing "
351                                    "arguments yet: %s",
352                                    args[distinguishingIndex].location)
353
354            # Convert all our arguments up to the distinguishing index.
355            # Doesn't matter which of the possible signatures we use, since
356            # they all have the same types up to that point; just use
357            # possibleSignatures[0]
358            caseBody = [
359                CGArgumentConverter(possibleSignatures[0][1][i],
360                                    i, "args", "argc", descriptor)
361                for i in range(0, distinguishingIndex)]
362
363            # Select the right overload from our set.
364            distinguishingArg = "args.get(%d)" % distinguishingIndex
365
366            def pickFirstSignature(condition, filterLambda):
367                sigs = filter(filterLambda, possibleSignatures)
368                assert len(sigs) < 2
369                if len(sigs) > 0:
370                    call = getPerSignatureCall(sigs[0], distinguishingIndex)
371                    if condition is None:
372                        caseBody.append(call)
373                    else:
374                        caseBody.append(CGGeneric("if " + condition + " {"))
375                        caseBody.append(CGIndenter(call))
376                        caseBody.append(CGGeneric("}"))
377                    return True
378                return False
379
380            # First check for null or undefined
381            pickFirstSignature("%s.get().is_null_or_undefined()" % distinguishingArg,
382                               lambda s: (s[1][distinguishingIndex].type.nullable() or
383                                          s[1][distinguishingIndex].type.isDictionary()))
384
385            # Now check for distinguishingArg being an object that implements a
386            # non-callback interface.  That includes typed arrays and
387            # arraybuffers.
388            interfacesSigs = [
389                s for s in possibleSignatures
390                if (s[1][distinguishingIndex].type.isObject() or
391                    s[1][distinguishingIndex].type.isNonCallbackInterface())]
392            # There might be more than one of these; we need to check
393            # which ones we unwrap to.
394
395            if len(interfacesSigs) > 0:
396                # The spec says that we should check for "platform objects
397                # implementing an interface", but it's enough to guard on these
398                # being an object.  The code for unwrapping non-callback
399                # interfaces and typed arrays will just bail out and move on to
400                # the next overload if the object fails to unwrap correctly.  We
401                # could even not do the isObject() check up front here, but in
402                # cases where we have multiple object overloads it makes sense
403                # to do it only once instead of for each overload.  That will
404                # also allow the unwrapping test to skip having to do codegen
405                # for the null-or-undefined case, which we already handled
406                # above.
407                caseBody.append(CGGeneric("if %s.get().is_object() {" %
408                                          (distinguishingArg)))
409                for idx, sig in enumerate(interfacesSigs):
410                    caseBody.append(CGIndenter(CGGeneric("loop {")))
411                    type = sig[1][distinguishingIndex].type
412
413                    # The argument at index distinguishingIndex can't possibly
414                    # be unset here, because we've already checked that argc is
415                    # large enough that we can examine this argument.
416                    info = getJSToNativeConversionInfo(
417                        type, descriptor, failureCode="break;", isDefinitelyObject=True)
418                    template = info.template
419                    declType = info.declType
420
421                    testCode = instantiateJSToNativeConversionTemplate(
422                        template,
423                        {"val": distinguishingArg},
424                        declType,
425                        "arg%d" % distinguishingIndex)
426
427                    # Indent by 4, since we need to indent further than our "do" statement
428                    caseBody.append(CGIndenter(testCode, 4))
429                    # If we got this far, we know we unwrapped to the right
430                    # interface, so just do the call.  Start conversion with
431                    # distinguishingIndex + 1, since we already converted
432                    # distinguishingIndex.
433                    caseBody.append(CGIndenter(
434                        getPerSignatureCall(sig, distinguishingIndex + 1), 4))
435                    caseBody.append(CGIndenter(CGGeneric("}")))
436
437                caseBody.append(CGGeneric("}"))
438
439            # XXXbz Now we're supposed to check for distinguishingArg being
440            # an array or a platform object that supports indexed
441            # properties... skip that last for now.  It's a bit of a pain.
442            pickFirstSignature("%s.get().is_object() && is_array_like(cx, %s)" %
443                               (distinguishingArg, distinguishingArg),
444                               lambda s:
445                                   (s[1][distinguishingIndex].type.isSequence() or
446                                    s[1][distinguishingIndex].type.isObject()))
447
448            # Check for Date objects
449            # XXXbz Do we need to worry about security wrappers around the Date?
450            pickFirstSignature("%s.get().is_object() && "
451                               "{ rooted!(in(cx) let obj = %s.get().to_object()); "
452                               "let mut is_date = false; "
453                               "assert!(JS_ObjectIsDate(cx, obj.handle(), &mut is_date)); "
454                               "is_date }" %
455                               (distinguishingArg, distinguishingArg),
456                               lambda s: (s[1][distinguishingIndex].type.isDate() or
457                                          s[1][distinguishingIndex].type.isObject()))
458
459            # Check for vanilla JS objects
460            # XXXbz Do we need to worry about security wrappers?
461            pickFirstSignature("%s.get().is_object() && !is_platform_object(%s.get().to_object())" %
462                               (distinguishingArg, distinguishingArg),
463                               lambda s: (s[1][distinguishingIndex].type.isCallback() or
464                                          s[1][distinguishingIndex].type.isCallbackInterface() or
465                                          s[1][distinguishingIndex].type.isDictionary() or
466                                          s[1][distinguishingIndex].type.isObject()))
467
468            # The remaining cases are mutually exclusive.  The
469            # pickFirstSignature calls are what change caseBody
470            # Check for strings or enums
471            if pickFirstSignature(None,
472                                  lambda s: (s[1][distinguishingIndex].type.isString() or
473                                             s[1][distinguishingIndex].type.isEnum())):
474                pass
475            # Check for primitives
476            elif pickFirstSignature(None,
477                                    lambda s: s[1][distinguishingIndex].type.isPrimitive()):
478                pass
479            # Check for "any"
480            elif pickFirstSignature(None,
481                                    lambda s: s[1][distinguishingIndex].type.isAny()):
482                pass
483            else:
484                # Just throw; we have no idea what we're supposed to
485                # do with this.
486                caseBody.append(CGGeneric("throw_internal_error(cx, \"Could not convert JavaScript argument\");\n"
487                                          "return false;"))
488
489            argCountCases.append(CGCase(str(argCount),
490                                        CGList(caseBody, "\n")))
491
492        overloadCGThings = []
493        overloadCGThings.append(
494            CGGeneric("let argcount = cmp::min(argc, %d);" %
495                      maxArgCount))
496        overloadCGThings.append(
497            CGSwitch("argcount",
498                     argCountCases,
499                     CGGeneric("throw_type_error(cx, \"Not enough arguments to %s.\");\n"
500                               "return false;" % methodName)))
501        # XXXjdm Avoid unreachable statement warnings
502        # overloadCGThings.append(
503        #     CGGeneric('panic!("We have an always-returning default case");\n'
504        #               'return false;'))
505        self.cgRoot = CGWrapper(CGList(overloadCGThings, "\n"),
506                                pre="\n")
507
508    def define(self):
509        return self.cgRoot.define()
510
511
512def dictionaryHasSequenceMember(dictionary):
513    return (any(typeIsSequenceOrHasSequenceMember(m.type) for m in
514                dictionary.members) or
515            (dictionary.parent and
516             dictionaryHasSequenceMember(dictionary.parent)))
517
518
519def typeIsSequenceOrHasSequenceMember(type):
520    if type.nullable():
521        type = type.inner
522    if type.isSequence():
523        return True
524    if type.isDictionary():
525        return dictionaryHasSequenceMember(type.inner)
526    if type.isUnion():
527        return any(typeIsSequenceOrHasSequenceMember(m.type) for m in
528                   type.flatMemberTypes)
529    return False
530
531
532def union_native_type(t):
533    name = t.unroll().name
534    return 'UnionTypes::%s' % name
535
536
537class JSToNativeConversionInfo():
538    """
539    An object representing information about a JS-to-native conversion.
540    """
541    def __init__(self, template, default=None, declType=None):
542        """
543        template: A string representing the conversion code.  This will have
544                  template substitution performed on it as follows:
545
546          ${val} is a handle to the JS::Value in question
547
548        default: A string or None representing rust code for default value(if any).
549
550        declType: A CGThing representing the native C++ type we're converting
551                  to.  This is allowed to be None if the conversion code is
552                  supposed to be used as-is.
553        """
554        assert isinstance(template, str)
555        assert declType is None or isinstance(declType, CGThing)
556        self.template = template
557        self.default = default
558        self.declType = declType
559
560
561def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
562                                isDefinitelyObject=False,
563                                isMember=False,
564                                isArgument=False,
565                                isAutoRooted=False,
566                                invalidEnumValueFatal=True,
567                                defaultValue=None,
568                                treatNullAs="Default",
569                                isEnforceRange=False,
570                                isClamp=False,
571                                exceptionCode=None,
572                                allowTreatNonObjectAsNull=False,
573                                isCallbackReturnValue=False,
574                                sourceDescription="value"):
575    """
576    Get a template for converting a JS value to a native object based on the
577    given type and descriptor.  If failureCode is given, then we're actually
578    testing whether we can convert the argument to the desired type.  That
579    means that failures to convert due to the JS value being the wrong type of
580    value need to use failureCode instead of throwing exceptions.  Failures to
581    convert that are due to JS exceptions (from toString or valueOf methods) or
582    out of memory conditions need to throw exceptions no matter what
583    failureCode is.
584
585    If isDefinitelyObject is True, that means we know the value
586    isObject() and we have no need to recheck that.
587
588    isMember is `False`, "Dictionary", "Union" or "Variadic", and affects
589    whether this function returns code suitable for an on-stack rooted binding
590    or suitable for storing in an appropriate larger structure.
591
592    invalidEnumValueFatal controls whether an invalid enum value conversion
593    attempt will throw (if true) or simply return without doing anything (if
594    false).
595
596    If defaultValue is not None, it's the IDL default value for this conversion
597
598    If isEnforceRange is true, we're converting an integer and throwing if the
599    value is out of range.
600
601    If isClamp is true, we're converting an integer and clamping if the
602    value is out of range.
603
604    If allowTreatNonObjectAsNull is true, then [TreatNonObjectAsNull]
605    extended attributes on nullable callback functions will be honored.
606
607    The return value from this function is an object of JSToNativeConversionInfo consisting of four things:
608
609    1)  A string representing the conversion code.  This will have template
610        substitution performed on it as follows:
611
612          ${val} replaced by an expression for the JS::Value in question
613
614    2)  A string or None representing Rust code for the default value (if any).
615
616    3)  A CGThing representing the native C++ type we're converting to
617        (declType).  This is allowed to be None if the conversion code is
618        supposed to be used as-is.
619
620    4)  A boolean indicating whether the caller has to root the result.
621
622    """
623    # We should not have a defaultValue if we know we're an object
624    assert not isDefinitelyObject or defaultValue is None
625
626    # If exceptionCode is not set, we'll just rethrow the exception we got.
627    # Note that we can't just set failureCode to exceptionCode, because setting
628    # failureCode will prevent pending exceptions from being set in cases when
629    # they really should be!
630    if exceptionCode is None:
631        exceptionCode = "return false;\n"
632
633    if failureCode is None:
634        failOrPropagate = "throw_type_error(cx, &error);\n%s" % exceptionCode
635    else:
636        failOrPropagate = failureCode
637
638    def handleOptional(template, declType, default):
639        assert (defaultValue is None) == (default is None)
640        return JSToNativeConversionInfo(template, default, declType)
641
642    # Unfortunately, .capitalize() on a string will lowercase things inside the
643    # string, which we do not want.
644    def firstCap(string):
645        return string[0].upper() + string[1:]
646
647    # Helper functions for dealing with failures due to the JS value being the
648    # wrong type of value.
649    def onFailureNotAnObject(failureCode):
650        return CGWrapper(
651            CGGeneric(
652                failureCode or
653                ('throw_type_error(cx, "%s is not an object.");\n'
654                 '%s' % (firstCap(sourceDescription), exceptionCode))),
655            post="\n")
656
657    def onFailureInvalidEnumValue(failureCode, passedVarName):
658        return CGGeneric(
659            failureCode or
660            ('throw_type_error(cx, &format!("\'{}\' is not a valid enum value for enumeration \'%s\'.", %s)); %s'
661             % (type.name, passedVarName, exceptionCode)))
662
663    def onFailureNotCallable(failureCode):
664        return CGGeneric(
665            failureCode or
666            ('throw_type_error(cx, \"%s is not callable.\");\n'
667             '%s' % (firstCap(sourceDescription), exceptionCode)))
668
669    # A helper function for handling null default values. Checks that the
670    # default value, if it exists, is null.
671    def handleDefaultNull(nullValue):
672        if defaultValue is None:
673            return None
674
675        if not isinstance(defaultValue, IDLNullValue):
676            raise TypeError("Can't handle non-null default value here")
677
678        assert type.nullable() or type.isDictionary()
679        return nullValue
680
681    # A helper function for wrapping up the template body for
682    # possibly-nullable objecty stuff
683    def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type,
684                           failureCode=None):
685        if not isDefinitelyObject:
686            # Handle the non-object cases by wrapping up the whole
687            # thing in an if cascade.
688            templateBody = (
689                "if ${val}.get().is_object() {\n" +
690                CGIndenter(CGGeneric(templateBody)).define() + "\n")
691            if type.nullable():
692                templateBody += (
693                    "} else if ${val}.get().is_null_or_undefined() {\n"
694                    "    %s\n") % nullValue
695            templateBody += (
696                "} else {\n" +
697                CGIndenter(onFailureNotAnObject(failureCode)).define() +
698                "}")
699        return templateBody
700
701    assert not (isEnforceRange and isClamp)  # These are mutually exclusive
702
703    if type.isSequence() or type.isRecord():
704        innerInfo = getJSToNativeConversionInfo(innerContainerType(type),
705                                                descriptorProvider,
706                                                isMember=isMember,
707                                                isAutoRooted=isAutoRooted)
708        declType = wrapInNativeContainerType(type, innerInfo.declType)
709        config = getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs)
710
711        if type.nullable():
712            declType = CGWrapper(declType, pre="Option<", post=" >")
713
714        templateBody = ("match FromJSValConvertible::from_jsval(cx, ${val}, %s) {\n"
715                        "    Ok(ConversionResult::Success(value)) => value,\n"
716                        "    Ok(ConversionResult::Failure(error)) => {\n"
717                        "%s\n"
718                        "    }\n"
719                        "    _ => { %s },\n"
720                        "}" % (config, indent(failOrPropagate, 8), exceptionCode))
721
722        return handleOptional(templateBody, declType, handleDefaultNull("None"))
723
724    if type.isUnion():
725        declType = CGGeneric(union_native_type(type))
726        if type.nullable():
727            declType = CGWrapper(declType, pre="Option<", post=" >")
728
729        templateBody = ("match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
730                        "    Ok(ConversionResult::Success(value)) => value,\n"
731                        "    Ok(ConversionResult::Failure(error)) => {\n"
732                        "%s\n"
733                        "    }\n"
734                        "    _ => { %s },\n"
735                        "}" % (indent(failOrPropagate, 8), exceptionCode))
736
737        dictionaries = [
738            memberType
739            for memberType in type.unroll().flatMemberTypes
740            if memberType.isDictionary()
741        ]
742        if dictionaries:
743            if defaultValue:
744                assert isinstance(defaultValue, IDLNullValue)
745                dictionary, = dictionaries
746                default = "%s::%s(%s::%s::empty(cx))" % (
747                    union_native_type(type),
748                    dictionary.name,
749                    CGDictionary.makeModuleName(dictionary.inner),
750                    CGDictionary.makeDictionaryName(dictionary.inner))
751            else:
752                default = None
753        else:
754            default = handleDefaultNull("None")
755
756        return handleOptional(templateBody, declType, default)
757
758    if type.isPromise():
759        assert not type.nullable()
760        # Per spec, what we're supposed to do is take the original
761        # Promise.resolve and call it with the original Promise as this
762        # value to make a Promise out of whatever value we actually have
763        # here.  The question is which global we should use.  There are
764        # a couple cases to consider:
765        #
766        # 1) Normal call to API with a Promise argument.  This is a case the
767        #    spec covers, and we should be using the current Realm's
768        #    Promise.  That means the current compartment.
769        # 2) Promise return value from a callback or callback interface.
770        #    This is in theory a case the spec covers but in practice it
771        #    really doesn't define behavior here because it doesn't define
772        #    what Realm we're in after the callback returns, which is when
773        #    the argument conversion happens.  We will use the current
774        #    compartment, which is the compartment of the callable (which
775        #    may itself be a cross-compartment wrapper itself), which makes
776        #    as much sense as anything else. In practice, such an API would
777        #    once again be providing a Promise to signal completion of an
778        #    operation, which would then not be exposed to anyone other than
779        #    our own implementation code.
780        templateBody = fill(
781            """
782            { // Scope for our JSAutoCompartment.
783
784                rooted!(in(cx) let globalObj = CurrentGlobalOrNull(cx));
785                let promiseGlobal = GlobalScope::from_object_maybe_wrapped(globalObj.handle().get());
786
787                rooted!(in(cx) let mut valueToResolve = $${val}.get());
788                if !JS_WrapValue(cx, valueToResolve.handle_mut()) {
789                $*{exceptionCode}
790                }
791                match Promise::new_resolved(&promiseGlobal, cx, valueToResolve.handle()) {
792                    Ok(value) => value,
793                    Err(error) => {
794                    throw_dom_exception(cx, &promiseGlobal, error);
795                    $*{exceptionCode}
796                    }
797                }
798            }
799            """,
800            exceptionCode=exceptionCode)
801
802        if isArgument:
803            declType = CGGeneric("&Promise")
804        else:
805            declType = CGGeneric("Rc<Promise>")
806        return handleOptional(templateBody, declType, handleDefaultNull("None"))
807
808    if type.isGeckoInterface():
809        assert not isEnforceRange and not isClamp
810
811        descriptor = descriptorProvider.getDescriptor(
812            type.unroll().inner.identifier.name)
813
814        if descriptor.interface.isCallback():
815            name = descriptor.nativeType
816            declType = CGWrapper(CGGeneric(name), pre="Rc<", post=">")
817            template = "%s::new(cx, ${val}.get().to_object())" % name
818            if type.nullable():
819                declType = CGWrapper(declType, pre="Option<", post=">")
820                template = wrapObjectTemplate("Some(%s)" % template, "None",
821                                              isDefinitelyObject, type,
822                                              failureCode)
823
824            return handleOptional(template, declType, handleDefaultNull("None"))
825
826        conversionFunction = "root_from_handlevalue"
827        descriptorType = descriptor.returnType
828        if isMember == "Variadic":
829            conversionFunction = "native_from_handlevalue"
830            descriptorType = descriptor.nativeType
831        elif isArgument:
832            descriptorType = descriptor.argumentType
833
834        if descriptor.interface.isConsequential():
835            raise TypeError("Consequential interface %s being used as an "
836                            "argument" % descriptor.interface.identifier.name)
837
838        if failureCode is None:
839            substitutions = {
840                "sourceDescription": sourceDescription,
841                "interface": descriptor.interface.identifier.name,
842                "exceptionCode": exceptionCode,
843            }
844            unwrapFailureCode = string.Template(
845                'throw_type_error(cx, "${sourceDescription} does not '
846                'implement interface ${interface}.");\n'
847                '${exceptionCode}').substitute(substitutions)
848        else:
849            unwrapFailureCode = failureCode
850
851        templateBody = fill(
852            """
853            match ${function}($${val}) {
854                Ok(val) => val,
855                Err(()) => {
856                    $*{failureCode}
857                }
858            }
859            """,
860            failureCode=unwrapFailureCode + "\n",
861            function=conversionFunction)
862
863        declType = CGGeneric(descriptorType)
864        if type.nullable():
865            templateBody = "Some(%s)" % templateBody
866            declType = CGWrapper(declType, pre="Option<", post=">")
867
868        templateBody = wrapObjectTemplate(templateBody, "None",
869                                          isDefinitelyObject, type, failureCode)
870
871        return handleOptional(templateBody, declType, handleDefaultNull("None"))
872
873    if type.isSpiderMonkeyInterface():
874        raise TypeError("Can't handle SpiderMonkey interface arguments yet")
875
876    if type.isDOMString():
877        nullBehavior = getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs)
878
879        conversionCode = (
880            "match FromJSValConvertible::from_jsval(cx, ${val}, %s) {\n"
881            "    Ok(ConversionResult::Success(strval)) => strval,\n"
882            "    Ok(ConversionResult::Failure(error)) => {\n"
883            "%s\n"
884            "    }\n"
885            "    _ => { %s },\n"
886            "}" % (nullBehavior, indent(failOrPropagate, 8), exceptionCode))
887
888        if defaultValue is None:
889            default = None
890        elif isinstance(defaultValue, IDLNullValue):
891            assert type.nullable()
892            default = "None"
893        else:
894            assert defaultValue.type.tag() == IDLType.Tags.domstring
895            default = 'DOMString::from("%s")' % defaultValue.value
896            if type.nullable():
897                default = "Some(%s)" % default
898
899        declType = "DOMString"
900        if type.nullable():
901            declType = "Option<%s>" % declType
902
903        return handleOptional(conversionCode, CGGeneric(declType), default)
904
905    if type.isUSVString():
906        assert not isEnforceRange and not isClamp
907
908        conversionCode = (
909            "match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
910            "    Ok(ConversionResult::Success(strval)) => strval,\n"
911            "    Ok(ConversionResult::Failure(error)) => {\n"
912            "%s\n"
913            "    }\n"
914            "    _ => { %s },\n"
915            "}" % (indent(failOrPropagate, 8), exceptionCode))
916
917        if defaultValue is None:
918            default = None
919        elif isinstance(defaultValue, IDLNullValue):
920            assert type.nullable()
921            default = "None"
922        else:
923            assert defaultValue.type.tag() in (IDLType.Tags.domstring, IDLType.Tags.usvstring)
924            default = 'USVString("%s".to_owned())' % defaultValue.value
925            if type.nullable():
926                default = "Some(%s)" % default
927
928        declType = "USVString"
929        if type.nullable():
930            declType = "Option<%s>" % declType
931
932        return handleOptional(conversionCode, CGGeneric(declType), default)
933
934    if type.isByteString():
935        assert not isEnforceRange and not isClamp
936
937        conversionCode = (
938            "match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
939            "    Ok(ConversionResult::Success(strval)) => strval,\n"
940            "    Ok(ConversionResult::Failure(error)) => {\n"
941            "%s\n"
942            "    }\n"
943            "    _ => { %s },\n"
944            "}" % (indent(failOrPropagate, 8), exceptionCode))
945
946        if defaultValue is None:
947            default = None
948        elif isinstance(defaultValue, IDLNullValue):
949            assert type.nullable()
950            default = "None"
951        else:
952            assert defaultValue.type.tag() in (IDLType.Tags.domstring, IDLType.Tags.bytestring)
953            default = 'ByteString::new(b"%s".to_vec())' % defaultValue.value
954            if type.nullable():
955                default = "Some(%s)" % default
956
957        declType = "ByteString"
958        if type.nullable():
959            declType = "Option<%s>" % declType
960
961        return handleOptional(conversionCode, CGGeneric(declType), default)
962
963    if type.isEnum():
964        assert not isEnforceRange and not isClamp
965
966        if type.nullable():
967            raise TypeError("We don't support nullable enumerated arguments "
968                            "yet")
969        enum = type.inner.identifier.name
970        if invalidEnumValueFatal:
971            handleInvalidEnumValueCode = onFailureInvalidEnumValue(failureCode, 'search').define()
972        else:
973            handleInvalidEnumValueCode = "return true;"
974
975        template = (
976            "match find_enum_value(cx, ${val}, %(pairs)s) {\n"
977            "    Err(_) => { %(exceptionCode)s },\n"
978            "    Ok((None, search)) => { %(handleInvalidEnumValueCode)s },\n"
979            "    Ok((Some(&value), _)) => value,\n"
980            "}" % {"pairs": enum + "Values::pairs",
981                   "exceptionCode": exceptionCode,
982                   "handleInvalidEnumValueCode": handleInvalidEnumValueCode})
983
984        if defaultValue is not None:
985            assert defaultValue.type.tag() == IDLType.Tags.domstring
986            default = "%s::%s" % (enum, getEnumValueName(defaultValue.value))
987        else:
988            default = None
989
990        return handleOptional(template, CGGeneric(enum), default)
991
992    if type.isCallback():
993        assert not isEnforceRange and not isClamp
994        assert not type.treatNonCallableAsNull()
995        assert not type.treatNonObjectAsNull() or type.nullable()
996        assert not type.treatNonObjectAsNull() or not type.treatNonCallableAsNull()
997
998        callback = type.unroll().callback
999        declType = CGGeneric(callback.identifier.name)
1000        finalDeclType = CGTemplatedType("Rc", declType)
1001
1002        conversion = CGCallbackTempRoot(declType.define())
1003
1004        if type.nullable():
1005            declType = CGTemplatedType("Option", declType)
1006            finalDeclType = CGTemplatedType("Option", finalDeclType)
1007            conversion = CGWrapper(conversion, pre="Some(", post=")")
1008
1009        if allowTreatNonObjectAsNull and type.treatNonObjectAsNull():
1010            if not isDefinitelyObject:
1011                haveObject = "${val}.get().is_object()"
1012                template = CGIfElseWrapper(haveObject,
1013                                           conversion,
1014                                           CGGeneric("None")).define()
1015            else:
1016                template = conversion
1017        else:
1018            template = CGIfElseWrapper("IsCallable(${val}.get().to_object())",
1019                                       conversion,
1020                                       onFailureNotCallable(failureCode)).define()
1021            template = wrapObjectTemplate(
1022                template,
1023                "None",
1024                isDefinitelyObject,
1025                type,
1026                failureCode)
1027
1028        if defaultValue is not None:
1029            assert allowTreatNonObjectAsNull
1030            assert type.treatNonObjectAsNull()
1031            assert type.nullable()
1032            assert isinstance(defaultValue, IDLNullValue)
1033            default = "None"
1034        else:
1035            default = None
1036
1037        return JSToNativeConversionInfo(template, default, finalDeclType)
1038
1039    if type.isAny():
1040        assert not isEnforceRange and not isClamp
1041        assert isMember != "Union"
1042
1043        if isMember == "Dictionary" or isAutoRooted:
1044            # TODO: Need to properly root dictionaries
1045            # https://github.com/servo/servo/issues/6381
1046            if isMember == "Dictionary":
1047                declType = CGGeneric("Heap<JSVal>")
1048            # AutoRooter can trace properly inner raw GC thing pointers
1049            else:
1050                declType = CGGeneric("JSVal")
1051
1052            if defaultValue is None:
1053                default = None
1054            elif isinstance(defaultValue, IDLNullValue):
1055                default = "NullValue()"
1056            elif isinstance(defaultValue, IDLUndefinedValue):
1057                default = "UndefinedValue()"
1058            else:
1059                raise TypeError("Can't handle non-null, non-undefined default value here")
1060            return handleOptional("${val}.get()", declType, default)
1061
1062        declType = CGGeneric("HandleValue")
1063
1064        if defaultValue is None:
1065            default = None
1066        elif isinstance(defaultValue, IDLNullValue):
1067            default = "HandleValue::null()"
1068        elif isinstance(defaultValue, IDLUndefinedValue):
1069            default = "HandleValue::undefined()"
1070        else:
1071            raise TypeError("Can't handle non-null, non-undefined default value here")
1072
1073        return handleOptional("${val}", declType, default)
1074
1075    if type.isObject():
1076        assert not isEnforceRange and not isClamp
1077
1078        # TODO: Need to root somehow
1079        # https://github.com/servo/servo/issues/6382
1080        default = "ptr::null_mut()"
1081        templateBody = wrapObjectTemplate("${val}.get().to_object()",
1082                                          default,
1083                                          isDefinitelyObject, type, failureCode)
1084
1085        if isMember in ("Dictionary", "Union"):
1086            declType = CGGeneric("Heap<*mut JSObject>")
1087        else:
1088            # TODO: Need to root somehow
1089            # https://github.com/servo/servo/issues/6382
1090            declType = CGGeneric("*mut JSObject")
1091
1092        return handleOptional(templateBody, declType,
1093                              handleDefaultNull(default))
1094
1095    if type.isDictionary():
1096        # There are no nullable dictionaries
1097        assert not type.nullable()
1098
1099        typeName = "%s::%s" % (CGDictionary.makeModuleName(type.inner),
1100                               CGDictionary.makeDictionaryName(type.inner))
1101        declType = CGGeneric(typeName)
1102        empty = "%s::empty(cx)" % typeName
1103
1104        if type_needs_tracing(type):
1105            declType = CGTemplatedType("RootedTraceableBox", declType)
1106
1107        template = ("match FromJSValConvertible::from_jsval(cx, ${val}, ()) {\n"
1108                    "    Ok(ConversionResult::Success(dictionary)) => dictionary,\n"
1109                    "    Ok(ConversionResult::Failure(error)) => {\n"
1110                    "%s\n"
1111                    "    }\n"
1112                    "    _ => { %s },\n"
1113                    "}" % (indent(failOrPropagate, 8), exceptionCode))
1114
1115        return handleOptional(template, declType, handleDefaultNull(empty))
1116
1117    if type.isVoid():
1118        # This one only happens for return values, and its easy: Just
1119        # ignore the jsval.
1120        return JSToNativeConversionInfo("", None, None)
1121
1122    if not type.isPrimitive():
1123        raise TypeError("Need conversion for argument type '%s'" % str(type))
1124
1125    conversionBehavior = getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs)
1126
1127    if failureCode is None:
1128        failureCode = 'return false'
1129
1130    declType = CGGeneric(builtinNames[type.tag()])
1131    if type.nullable():
1132        declType = CGWrapper(declType, pre="Option<", post=">")
1133
1134    template = (
1135        "match FromJSValConvertible::from_jsval(cx, ${val}, %s) {\n"
1136        "    Ok(ConversionResult::Success(v)) => v,\n"
1137        "    Ok(ConversionResult::Failure(error)) => {\n"
1138        "%s\n"
1139        "    }\n"
1140        "    _ => { %s }\n"
1141        "}" % (conversionBehavior, indent(failOrPropagate, 8), exceptionCode))
1142
1143    if defaultValue is not None:
1144        if isinstance(defaultValue, IDLNullValue):
1145            assert type.nullable()
1146            defaultStr = "None"
1147        else:
1148            tag = defaultValue.type.tag()
1149            if tag in [IDLType.Tags.float, IDLType.Tags.double]:
1150                defaultStr = "Finite::wrap(%s)" % defaultValue.value
1151            elif tag in numericTags:
1152                defaultStr = str(defaultValue.value)
1153            else:
1154                assert tag == IDLType.Tags.bool
1155                defaultStr = toStringBool(defaultValue.value)
1156
1157            if type.nullable():
1158                defaultStr = "Some(%s)" % defaultStr
1159    else:
1160        defaultStr = None
1161
1162    return handleOptional(template, declType, defaultStr)
1163
1164
1165def instantiateJSToNativeConversionTemplate(templateBody, replacements,
1166                                            declType, declName):
1167    """
1168    Take the templateBody and declType as returned by
1169    getJSToNativeConversionInfo, a set of replacements as required by the
1170    strings in such a templateBody, and a declName, and generate code to
1171    convert into a stack Rust binding with that name.
1172    """
1173    result = CGList([], "\n")
1174
1175    conversion = CGGeneric(string.Template(templateBody).substitute(replacements))
1176
1177    if declType is not None:
1178        newDecl = [
1179            CGGeneric("let "),
1180            CGGeneric(declName),
1181            CGGeneric(": "),
1182            declType,
1183            CGGeneric(" = "),
1184            conversion,
1185            CGGeneric(";"),
1186        ]
1187        result.append(CGList(newDecl))
1188    else:
1189        result.append(conversion)
1190
1191    # Add an empty CGGeneric to get an extra newline after the argument
1192    # conversion.
1193    result.append(CGGeneric(""))
1194
1195    return result
1196
1197
1198def convertConstIDLValueToJSVal(value):
1199    if isinstance(value, IDLNullValue):
1200        return "ConstantVal::NullVal"
1201    tag = value.type.tag()
1202    if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
1203               IDLType.Tags.uint16, IDLType.Tags.int32]:
1204        return "ConstantVal::IntVal(%s)" % (value.value)
1205    if tag == IDLType.Tags.uint32:
1206        return "ConstantVal::UintVal(%s)" % (value.value)
1207    if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]:
1208        return "ConstantVal::DoubleVal(%s as f64)" % (value.value)
1209    if tag == IDLType.Tags.bool:
1210        return "ConstantVal::BoolVal(true)" if value.value else "ConstantVal::BoolVal(false)"
1211    if tag in [IDLType.Tags.unrestricted_float, IDLType.Tags.float,
1212               IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
1213        return "ConstantVal::DoubleVal(%s as f64)" % (value.value)
1214    raise TypeError("Const value of unhandled type: " + value.type)
1215
1216
1217class CGArgumentConverter(CGThing):
1218    """
1219    A class that takes an IDL argument object, its index in the
1220    argument list, and the argv and argc strings and generates code to
1221    unwrap the argument to the right native type.
1222    """
1223    def __init__(self, argument, index, args, argc, descriptorProvider,
1224                 invalidEnumValueFatal=True):
1225        CGThing.__init__(self)
1226        assert not argument.defaultValue or argument.optional
1227
1228        replacer = {
1229            "index": index,
1230            "argc": argc,
1231            "args": args
1232        }
1233
1234        replacementVariables = {
1235            "val": string.Template("${args}.get(${index})").substitute(replacer),
1236        }
1237
1238        info = getJSToNativeConversionInfo(
1239            argument.type,
1240            descriptorProvider,
1241            invalidEnumValueFatal=invalidEnumValueFatal,
1242            defaultValue=argument.defaultValue,
1243            treatNullAs=argument.treatNullAs,
1244            isEnforceRange=argument.enforceRange,
1245            isClamp=argument.clamp,
1246            isMember="Variadic" if argument.variadic else False,
1247            isAutoRooted=type_needs_auto_root(argument.type),
1248            allowTreatNonObjectAsNull=argument.allowTreatNonCallableAsNull())
1249        template = info.template
1250        default = info.default
1251        declType = info.declType
1252
1253        if not argument.variadic:
1254            if argument.optional:
1255                condition = "{args}.get({index}).is_undefined()".format(**replacer)
1256                if argument.defaultValue:
1257                    assert default
1258                    template = CGIfElseWrapper(condition,
1259                                               CGGeneric(default),
1260                                               CGGeneric(template)).define()
1261                else:
1262                    assert not default
1263                    declType = CGWrapper(declType, pre="Option<", post=">")
1264                    template = CGIfElseWrapper(condition,
1265                                               CGGeneric("None"),
1266                                               CGGeneric("Some(%s)" % template)).define()
1267            else:
1268                assert not default
1269
1270            arg = "arg%d" % index
1271
1272            self.converter = instantiateJSToNativeConversionTemplate(
1273                template, replacementVariables, declType, arg)
1274
1275            # The auto rooting is done only after the conversion is performed
1276            if type_needs_auto_root(argument.type):
1277                self.converter.append(CGGeneric("auto_root!(in(cx) let %s = %s);" % (arg, arg)))
1278
1279        else:
1280            assert argument.optional
1281            variadicConversion = {
1282                "val": string.Template("${args}.get(variadicArg)").substitute(replacer),
1283            }
1284            innerConverter = [instantiateJSToNativeConversionTemplate(
1285                template, variadicConversion, declType, "slot")]
1286
1287            arg = "arg%d" % index
1288            if argument.type.isGeckoInterface():
1289                init = "rooted_vec!(let mut %s)" % arg
1290                innerConverter.append(CGGeneric("%s.push(Dom::from_ref(&*slot));" % arg))
1291            else:
1292                init = "let mut %s = vec![]" % arg
1293                innerConverter.append(CGGeneric("%s.push(slot);" % arg))
1294            inner = CGIndenter(CGList(innerConverter, "\n"), 8).define()
1295
1296            self.converter = CGGeneric("""\
1297%(init)s;
1298if %(argc)s > %(index)s {
1299    %(arg)s.reserve(%(argc)s as usize - %(index)s);
1300    for variadicArg in %(index)s..%(argc)s {
1301%(inner)s
1302    }
1303}""" % {'arg': arg, 'argc': argc, 'index': index, 'inner': inner, 'init': init})
1304
1305    def define(self):
1306        return self.converter.define()
1307
1308
1309def wrapForType(jsvalRef, result='result', successCode='return true;', pre=''):
1310    """
1311    Reflect a Rust value into JS.
1312
1313      * 'jsvalRef': a MutableHandleValue in which to store the result
1314                    of the conversion;
1315      * 'result': the name of the variable in which the Rust value is stored;
1316      * 'successCode': the code to run once we have done the conversion.
1317      * 'pre': code to run before the conversion if rooting is necessary
1318    """
1319    wrap = "%s\n(%s).to_jsval(cx, %s);" % (pre, result, jsvalRef)
1320    if successCode:
1321        wrap += "\n%s" % successCode
1322    return wrap
1323
1324
1325def typeNeedsCx(type, retVal=False):
1326    if type is None:
1327        return False
1328    if type.nullable():
1329        type = type.inner
1330    if type.isSequence():
1331        type = type.inner
1332    if type.isUnion():
1333        return any(typeNeedsCx(t) for t in type.unroll().flatMemberTypes)
1334    if retVal and type.isSpiderMonkeyInterface():
1335        return True
1336    return type.isAny() or type.isObject()
1337
1338
1339# Returns a conversion behavior suitable for a type
1340def getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs):
1341    if type.isSequence() or type.isRecord():
1342        return getConversionConfigForType(innerContainerType(type), isEnforceRange, isClamp, treatNullAs)
1343    if type.isDOMString():
1344        assert not isEnforceRange and not isClamp
1345
1346        treatAs = {
1347            "Default": "StringificationBehavior::Default",
1348            "EmptyString": "StringificationBehavior::Empty",
1349        }
1350        if treatNullAs not in treatAs:
1351            raise TypeError("We don't support [TreatNullAs=%s]" % treatNullAs)
1352        if type.nullable():
1353            # Note: the actual behavior passed here doesn't matter for nullable
1354            # strings.
1355            return "StringificationBehavior::Default"
1356        else:
1357            return treatAs[treatNullAs]
1358    if type.isPrimitive() and type.isInteger():
1359        if isEnforceRange:
1360            return "ConversionBehavior::EnforceRange"
1361        elif isClamp:
1362            return "ConversionBehavior::Clamp"
1363        else:
1364            return "ConversionBehavior::Default"
1365    assert not isEnforceRange and not isClamp
1366    return "()"
1367
1368
1369# Returns a CGThing containing the type of the return value.
1370def getRetvalDeclarationForType(returnType, descriptorProvider):
1371    if returnType is None or returnType.isVoid():
1372        # Nothing to declare
1373        return CGGeneric("()")
1374    if returnType.isPrimitive() and returnType.tag() in builtinNames:
1375        result = CGGeneric(builtinNames[returnType.tag()])
1376        if returnType.nullable():
1377            result = CGWrapper(result, pre="Option<", post=">")
1378        return result
1379    if returnType.isDOMString():
1380        result = CGGeneric("DOMString")
1381        if returnType.nullable():
1382            result = CGWrapper(result, pre="Option<", post=">")
1383        return result
1384    if returnType.isUSVString():
1385        result = CGGeneric("USVString")
1386        if returnType.nullable():
1387            result = CGWrapper(result, pre="Option<", post=">")
1388        return result
1389    if returnType.isByteString():
1390        result = CGGeneric("ByteString")
1391        if returnType.nullable():
1392            result = CGWrapper(result, pre="Option<", post=">")
1393        return result
1394    if returnType.isEnum():
1395        result = CGGeneric(returnType.unroll().inner.identifier.name)
1396        if returnType.nullable():
1397            result = CGWrapper(result, pre="Option<", post=">")
1398        return result
1399    if returnType.isPromise():
1400        assert not returnType.nullable()
1401        return CGGeneric("Rc<Promise>")
1402    if returnType.isGeckoInterface():
1403        descriptor = descriptorProvider.getDescriptor(
1404            returnType.unroll().inner.identifier.name)
1405        result = CGGeneric(descriptor.returnType)
1406        if returnType.nullable():
1407            result = CGWrapper(result, pre="Option<", post=">")
1408        return result
1409    if returnType.isCallback():
1410        callback = returnType.unroll().callback
1411        result = CGGeneric('Rc<%s::%s>' % (getModuleFromObject(callback), callback.identifier.name))
1412        if returnType.nullable():
1413            result = CGWrapper(result, pre="Option<", post=">")
1414        return result
1415    if returnType.isUnion():
1416        result = CGGeneric(union_native_type(returnType))
1417        if returnType.nullable():
1418            result = CGWrapper(result, pre="Option<", post=">")
1419        return result
1420    # TODO: Return the value through a MutableHandleValue outparam
1421    # https://github.com/servo/servo/issues/6307
1422    if returnType.isAny():
1423        return CGGeneric("JSVal")
1424    if returnType.isObject() or returnType.isSpiderMonkeyInterface():
1425        result = CGGeneric("NonNull<JSObject>")
1426        if returnType.nullable():
1427            result = CGWrapper(result, pre="Option<", post=">")
1428        return result
1429    if returnType.isSequence() or returnType.isRecord():
1430        result = getRetvalDeclarationForType(innerContainerType(returnType), descriptorProvider)
1431        result = wrapInNativeContainerType(returnType, result)
1432        if returnType.nullable():
1433            result = CGWrapper(result, pre="Option<", post=">")
1434        return result
1435    if returnType.isDictionary():
1436        nullable = returnType.nullable()
1437        dictName = returnType.inner.name if nullable else returnType.name
1438        result = CGGeneric(dictName)
1439        if type_needs_tracing(returnType):
1440            result = CGWrapper(result, pre="RootedTraceableBox<", post=">")
1441        if nullable:
1442            result = CGWrapper(result, pre="Option<", post=">")
1443        return result
1444
1445    raise TypeError("Don't know how to declare return value for %s" %
1446                    returnType)
1447
1448
1449def MemberCondition(pref, func):
1450    """
1451    A string representing the condition for a member to actually be exposed.
1452    Any of the arguments can be None. If not None, they should have the
1453    following types:
1454
1455    pref: The name of the preference.
1456    func: The name of the function.
1457    """
1458    assert pref is None or isinstance(pref, str)
1459    assert func is None or isinstance(func, str)
1460    assert func is None or pref is None
1461    if pref:
1462        return 'Condition::Pref("%s")' % pref
1463    if func:
1464        return 'Condition::Func(%s)' % func
1465    return "Condition::Satisfied"
1466
1467
1468class PropertyDefiner:
1469    """
1470    A common superclass for defining things on prototype objects.
1471
1472    Subclasses should implement generateArray to generate the actual arrays of
1473    things we're defining. They should also set self.regular to the list of
1474    things exposed to web pages.
1475    """
1476    def __init__(self, descriptor, name):
1477        self.descriptor = descriptor
1478        self.name = name
1479
1480    def variableName(self):
1481        return "s" + self.name
1482
1483    def length(self):
1484        return len(self.regular)
1485
1486    def __str__(self):
1487        # We only need to generate id arrays for things that will end
1488        # up used via ResolveProperty or EnumerateProperties.
1489        return self.generateArray(self.regular, self.variableName())
1490
1491    @staticmethod
1492    def getStringAttr(member, name):
1493        attr = member.getExtendedAttribute(name)
1494        if attr is None:
1495            return None
1496        # It's a list of strings
1497        assert len(attr) == 1
1498        assert attr[0] is not None
1499        return attr[0]
1500
1501    @staticmethod
1502    def getControllingCondition(interfaceMember, descriptor):
1503        return MemberCondition(
1504            PropertyDefiner.getStringAttr(interfaceMember,
1505                                          "Pref"),
1506            PropertyDefiner.getStringAttr(interfaceMember,
1507                                          "Func"))
1508
1509    def generateGuardedArray(self, array, name, specTemplate, specTerminator,
1510                             specType, getCondition, getDataTuple):
1511        """
1512        This method generates our various arrays.
1513
1514        array is an array of interface members as passed to generateArray
1515
1516        name is the name as passed to generateArray
1517
1518        specTemplate is a template for each entry of the spec array
1519
1520        specTerminator is a terminator for the spec array (inserted at the end
1521          of the array), or None
1522
1523        specType is the actual typename of our spec
1524
1525        getDataTuple is a callback function that takes an array entry and
1526          returns a tuple suitable for substitution into specTemplate.
1527        """
1528
1529        # We generate an all-encompassing list of lists of specs, with each sublist
1530        # representing a group of members that share a common pref name. That will
1531        # make sure the order of the properties as exposed on the interface and
1532        # interface prototype objects does not change when pref control is added to
1533        # members while still allowing us to define all the members in the smallest
1534        # number of JSAPI calls.
1535        assert len(array) != 0
1536        specs = []
1537        prefableSpecs = []
1538        prefableTemplate = '    Guard::new(%s, %s[%d])'
1539
1540        for cond, members in groupby(array, lambda m: getCondition(m, self.descriptor)):
1541            currentSpecs = [specTemplate % getDataTuple(m) for m in members]
1542            if specTerminator:
1543                currentSpecs.append(specTerminator)
1544            specs.append("&[\n" + ",\n".join(currentSpecs) + "]\n")
1545            prefableSpecs.append(
1546                prefableTemplate % (cond, name + "_specs", len(specs) - 1))
1547
1548        specsArray = ("const %s_specs: &'static [&'static[%s]] = &[\n" +
1549                      ",\n".join(specs) + "\n" +
1550                      "];\n") % (name, specType)
1551
1552        prefArray = ("const %s: &'static [Guard<&'static [%s]>] = &[\n" +
1553                     ",\n".join(prefableSpecs) + "\n" +
1554                     "];\n") % (name, specType)
1555        return specsArray + prefArray
1556
1557
1558# The length of a method is the minimum of the lengths of the
1559# argument lists of all its overloads.
1560def methodLength(method):
1561    signatures = method.signatures()
1562    return min(
1563        len([arg for arg in arguments if not arg.optional and not arg.variadic])
1564        for (_, arguments) in signatures)
1565
1566
1567class MethodDefiner(PropertyDefiner):
1568    """
1569    A class for defining methods on a prototype object.
1570    """
1571    def __init__(self, descriptor, name, static, unforgeable):
1572        assert not (static and unforgeable)
1573        PropertyDefiner.__init__(self, descriptor, name)
1574
1575        # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822
1576        #       We should be able to check for special operations without an
1577        #       identifier. For now we check if the name starts with __
1578
1579        # Ignore non-static methods for callback interfaces
1580        if not descriptor.interface.isCallback() or static:
1581            methods = [m for m in descriptor.interface.members if
1582                       m.isMethod() and m.isStatic() == static and
1583                       not m.isIdentifierLess() and
1584                       MemberIsUnforgeable(m, descriptor) == unforgeable]
1585        else:
1586            methods = []
1587        self.regular = [{"name": m.identifier.name,
1588                         "methodInfo": not m.isStatic(),
1589                         "length": methodLength(m),
1590                         "condition": PropertyDefiner.getControllingCondition(m, descriptor)}
1591                        for m in methods]
1592
1593        # FIXME Check for an existing iterator on the interface first.
1594        if any(m.isGetter() and m.isIndexed() for m in methods):
1595            self.regular.append({"name": '@@iterator',
1596                                 "methodInfo": False,
1597                                 "selfHostedName": "ArrayValues",
1598                                 "length": 0,
1599                                 "condition": "Condition::Satisfied"})
1600
1601        # Generate the keys/values/entries aliases for value iterables.
1602        maplikeOrSetlikeOrIterable = descriptor.interface.maplikeOrSetlikeOrIterable
1603        if (not static and not unforgeable and
1604            (maplikeOrSetlikeOrIterable and
1605             maplikeOrSetlikeOrIterable.isIterable() and
1606             maplikeOrSetlikeOrIterable.isValueIterator())):
1607            # Add our keys/values/entries/forEach
1608            self.regular.append({
1609                "name": "keys",
1610                "methodInfo": False,
1611                "selfHostedName": "ArrayKeys",
1612                "length": 0,
1613                "condition": PropertyDefiner.getControllingCondition(m,
1614                                                                     descriptor)
1615            })
1616            self.regular.append({
1617                "name": "values",
1618                "methodInfo": False,
1619                "selfHostedName": "ArrayValues",
1620                "length": 0,
1621                "condition": PropertyDefiner.getControllingCondition(m,
1622                                                                     descriptor)
1623            })
1624            self.regular.append({
1625                "name": "entries",
1626                "methodInfo": False,
1627                "selfHostedName": "ArrayEntries",
1628                "length": 0,
1629                "condition": PropertyDefiner.getControllingCondition(m,
1630                                                                     descriptor)
1631            })
1632            self.regular.append({
1633                "name": "forEach",
1634                "methodInfo": False,
1635                "selfHostedName": "ArrayForEach",
1636                "length": 1,
1637                "condition": PropertyDefiner.getControllingCondition(m,
1638                                                                     descriptor)
1639            })
1640
1641        isUnforgeableInterface = bool(descriptor.interface.getExtendedAttribute("Unforgeable"))
1642        if not static and unforgeable == isUnforgeableInterface:
1643            stringifier = descriptor.operations['Stringifier']
1644            if stringifier:
1645                self.regular.append({
1646                    "name": "toString",
1647                    "nativeName": stringifier.identifier.name,
1648                    "length": 0,
1649                    "condition": PropertyDefiner.getControllingCondition(stringifier, descriptor)
1650                })
1651        self.unforgeable = unforgeable
1652
1653    def generateArray(self, array, name):
1654        if len(array) == 0:
1655            return ""
1656
1657        def condition(m, d):
1658            return m["condition"]
1659
1660        flags = "JSPROP_ENUMERATE"
1661        if self.unforgeable:
1662            flags += " | JSPROP_PERMANENT | JSPROP_READONLY"
1663
1664        def specData(m):
1665            # TODO: Use something like JS_FNSPEC
1666            # https://github.com/servo/servo/issues/6391
1667            if "selfHostedName" in m:
1668                selfHostedName = '%s as *const u8 as *const libc::c_char' % str_to_const_array(m["selfHostedName"])
1669                assert not m.get("methodInfo", True)
1670                accessor = "None"
1671                jitinfo = "0 as *const JSJitInfo"
1672            else:
1673                selfHostedName = "0 as *const libc::c_char"
1674                if m.get("methodInfo", True):
1675                    identifier = m.get("nativeName", m["name"])
1676                    # Go through an intermediate type here, because it's not
1677                    # easy to tell whether the methodinfo is a JSJitInfo or
1678                    # a JSTypedMethodJitInfo here.  The compiler knows, though,
1679                    # so let it do the work.
1680                    jitinfo = "&%s_methodinfo as *const _ as *const JSJitInfo" % identifier
1681                    accessor = "Some(generic_method)"
1682                else:
1683                    jitinfo = "0 as *const JSJitInfo"
1684                    accessor = 'Some(%s)' % m.get("nativeName", m["name"])
1685            if m["name"].startswith("@@"):
1686                return ('(SymbolCode::%s as i32 + 1)'
1687                        % m["name"][2:], accessor, jitinfo, m["length"], flags, selfHostedName)
1688            return (str_to_const_array(m["name"]), accessor, jitinfo, m["length"], flags, selfHostedName)
1689
1690        return self.generateGuardedArray(
1691            array, name,
1692            '    JSFunctionSpec {\n'
1693            '        name: %s as *const u8 as *const libc::c_char,\n'
1694            '        call: JSNativeWrapper { op: %s, info: %s },\n'
1695            '        nargs: %s,\n'
1696            '        flags: (%s) as u16,\n'
1697            '        selfHostedName: %s\n'
1698            '    }',
1699            '    JSFunctionSpec {\n'
1700            '        name: 0 as *const libc::c_char,\n'
1701            '        call: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo },\n'
1702            '        nargs: 0,\n'
1703            '        flags: 0,\n'
1704            '        selfHostedName: 0 as *const libc::c_char\n'
1705            '    }',
1706            'JSFunctionSpec',
1707            condition, specData)
1708
1709
1710class AttrDefiner(PropertyDefiner):
1711    def __init__(self, descriptor, name, static, unforgeable):
1712        assert not (static and unforgeable)
1713        PropertyDefiner.__init__(self, descriptor, name)
1714        self.name = name
1715        self.descriptor = descriptor
1716        self.regular = [
1717            m
1718            for m in descriptor.interface.members if
1719            m.isAttr() and m.isStatic() == static and
1720            MemberIsUnforgeable(m, descriptor) == unforgeable
1721        ]
1722        self.static = static
1723        self.unforgeable = unforgeable
1724
1725    def generateArray(self, array, name):
1726        if len(array) == 0:
1727            return ""
1728
1729        flags = "JSPROP_ENUMERATE | JSPROP_SHARED"
1730        if self.unforgeable:
1731            flags += " | JSPROP_PERMANENT"
1732
1733        def getter(attr):
1734            if self.static:
1735                accessor = 'get_' + self.descriptor.internalNameFor(attr.identifier.name)
1736                jitinfo = "0 as *const JSJitInfo"
1737            else:
1738                if attr.hasLenientThis():
1739                    accessor = "generic_lenient_getter"
1740                else:
1741                    accessor = "generic_getter"
1742                jitinfo = "&%s_getterinfo" % self.descriptor.internalNameFor(attr.identifier.name)
1743
1744            return ("JSNativeWrapper { op: Some(%(native)s), info: %(info)s }"
1745                    % {"info": jitinfo,
1746                       "native": accessor})
1747
1748        def setter(attr):
1749            if (attr.readonly and not attr.getExtendedAttribute("PutForwards")
1750                    and not attr.getExtendedAttribute("Replaceable")):
1751                return "JSNativeWrapper { op: None, info: 0 as *const JSJitInfo }"
1752
1753            if self.static:
1754                accessor = 'set_' + self.descriptor.internalNameFor(attr.identifier.name)
1755                jitinfo = "0 as *const JSJitInfo"
1756            else:
1757                if attr.hasLenientThis():
1758                    accessor = "generic_lenient_setter"
1759                else:
1760                    accessor = "generic_setter"
1761                jitinfo = "&%s_setterinfo" % self.descriptor.internalNameFor(attr.identifier.name)
1762
1763            return ("JSNativeWrapper { op: Some(%(native)s), info: %(info)s }"
1764                    % {"info": jitinfo,
1765                       "native": accessor})
1766
1767        def specData(attr):
1768            return (str_to_const_array(attr.identifier.name), flags, getter(attr),
1769                    setter(attr))
1770
1771        return self.generateGuardedArray(
1772            array, name,
1773            '    JSPropertySpec {\n'
1774            '        name: %s as *const u8 as *const libc::c_char,\n'
1775            '        flags: (%s) as u8,\n'
1776            '        getter: %s,\n'
1777            '        setter: %s\n'
1778            '    }',
1779            '    JSPropertySpec {\n'
1780            '        name: 0 as *const libc::c_char,\n'
1781            '        flags: 0,\n'
1782            '        getter: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo },\n'
1783            '        setter: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo }\n'
1784            '    }',
1785            'JSPropertySpec',
1786            PropertyDefiner.getControllingCondition, specData)
1787
1788
1789class ConstDefiner(PropertyDefiner):
1790    """
1791    A class for definining constants on the interface object
1792    """
1793    def __init__(self, descriptor, name):
1794        PropertyDefiner.__init__(self, descriptor, name)
1795        self.name = name
1796        self.regular = [m for m in descriptor.interface.members if m.isConst()]
1797
1798    def generateArray(self, array, name):
1799        if len(array) == 0:
1800            return ""
1801
1802        def specData(const):
1803            return (str_to_const_array(const.identifier.name),
1804                    convertConstIDLValueToJSVal(const.value))
1805
1806        return self.generateGuardedArray(
1807            array, name,
1808            '    ConstantSpec { name: %s, value: %s }',
1809            None,
1810            'ConstantSpec',
1811            PropertyDefiner.getControllingCondition, specData)
1812
1813# We'll want to insert the indent at the beginnings of lines, but we
1814# don't want to indent empty lines.  So only indent lines that have a
1815# non-newline character on them.
1816lineStartDetector = re.compile("^(?=[^\n])", re.MULTILINE)
1817
1818
1819class CGIndenter(CGThing):
1820    """
1821    A class that takes another CGThing and generates code that indents that
1822    CGThing by some number of spaces.  The default indent is two spaces.
1823    """
1824    def __init__(self, child, indentLevel=4):
1825        CGThing.__init__(self)
1826        self.child = child
1827        self.indent = " " * indentLevel
1828
1829    def define(self):
1830        defn = self.child.define()
1831        if defn != "":
1832            return re.sub(lineStartDetector, self.indent, defn)
1833        else:
1834            return defn
1835
1836
1837class CGWrapper(CGThing):
1838    """
1839    Generic CGThing that wraps other CGThings with pre and post text.
1840    """
1841    def __init__(self, child, pre="", post="", reindent=False):
1842        CGThing.__init__(self)
1843        self.child = child
1844        self.pre = pre
1845        self.post = post
1846        self.reindent = reindent
1847
1848    def define(self):
1849        defn = self.child.define()
1850        if self.reindent:
1851            # We don't use lineStartDetector because we don't want to
1852            # insert whitespace at the beginning of our _first_ line.
1853            defn = stripTrailingWhitespace(
1854                defn.replace("\n", "\n" + (" " * len(self.pre))))
1855        return self.pre + defn + self.post
1856
1857
1858class CGImports(CGWrapper):
1859    """
1860    Generates the appropriate import/use statements.
1861    """
1862    def __init__(self, child, descriptors, callbacks, dictionaries, enums, typedefs, imports, config,
1863                 ignored_warnings=None):
1864        """
1865        Adds a set of imports.
1866        """
1867        if ignored_warnings is None:
1868            ignored_warnings = [
1869                'non_camel_case_types',
1870                'non_upper_case_globals',
1871                'unused_imports',
1872                'unused_variables',
1873                'unused_assignments',
1874                'unused_mut',
1875            ]
1876
1877        def componentTypes(type):
1878            if type.isType() and type.nullable():
1879                type = type.unroll()
1880            if type.isUnion():
1881                return type.flatMemberTypes
1882            if type.isDictionary():
1883                return [type] + getTypesFromDictionary(type)
1884            if type.isSequence():
1885                return componentTypes(type.inner)
1886            return [type]
1887
1888        def isImportable(type):
1889            if not type.isType():
1890                assert (type.isInterface() or type.isDictionary() or
1891                        type.isEnum() or type.isNamespace())
1892                return True
1893            return not (type.builtin or type.isSequence() or type.isUnion())
1894
1895        def relatedTypesForSignatures(method):
1896            types = []
1897            for (returnType, arguments) in method.signatures():
1898                types += componentTypes(returnType)
1899                for arg in arguments:
1900                    types += componentTypes(arg.type)
1901            return types
1902
1903        def getIdentifier(t):
1904            if t.isType():
1905                if t.nullable():
1906                    t = t.inner
1907                if t.isCallback():
1908                    return t.callback.identifier
1909                return t.identifier
1910            assert t.isInterface() or t.isDictionary() or t.isEnum() or t.isNamespace()
1911            return t.identifier
1912
1913        def removeWrapperAndNullableTypes(types):
1914            normalized = []
1915            for t in types:
1916                while (t.isType() and t.nullable()) or isinstance(t, IDLWrapperType):
1917                    t = t.inner
1918                if isImportable(t):
1919                    normalized += [t]
1920            return normalized
1921
1922        types = []
1923        for d in descriptors:
1924            if not d.interface.isCallback():
1925                types += [d.interface]
1926
1927            if d.interface.isIteratorInterface():
1928                types += [d.interface.iterableInterface]
1929
1930            members = d.interface.members + d.interface.namedConstructors
1931            constructor = d.interface.ctor()
1932            if constructor:
1933                members += [constructor]
1934
1935            if d.proxy:
1936                members += [o for o in d.operations.values() if o]
1937
1938            for m in members:
1939                if m.isMethod():
1940                    types += relatedTypesForSignatures(m)
1941                elif m.isAttr():
1942                    types += componentTypes(m.type)
1943
1944        # Import the type names used in the callbacks that are being defined.
1945        for c in callbacks:
1946            types += relatedTypesForSignatures(c)
1947
1948        # Import the type names used in the dictionaries that are being defined.
1949        for d in dictionaries:
1950            types += componentTypes(d)
1951
1952        # Import the type names used in the typedefs that are being defined.
1953        for t in typedefs:
1954            if not t.innerType.isCallback():
1955                types += componentTypes(t.innerType)
1956
1957        # Normalize the types we've collected and remove any ones which can't be imported.
1958        types = removeWrapperAndNullableTypes(types)
1959
1960        descriptorProvider = config.getDescriptorProvider()
1961        extras = []
1962        for t in types:
1963            # Importing these types in the same module that defines them is an error.
1964            if t in dictionaries or t in enums:
1965                continue
1966            if t.isInterface() or t.isNamespace():
1967                name = getIdentifier(t).name
1968                descriptor = descriptorProvider.getDescriptor(name)
1969                if name != 'GlobalScope':
1970                    extras += [descriptor.path]
1971                parentName = descriptor.getParentName()
1972                if parentName:
1973                    descriptor = descriptorProvider.getDescriptor(parentName)
1974                    extras += [descriptor.path, descriptor.bindingPath]
1975            elif t.isType() and t.isRecord():
1976                extras += ['dom::bindings::mozmap::MozMap']
1977            elif isinstance(t, IDLPromiseType):
1978                extras += ["dom::promise::Promise"]
1979            else:
1980                if t.isEnum():
1981                    extras += [getModuleFromObject(t) + '::' + getIdentifier(t).name + 'Values']
1982                extras += [getModuleFromObject(t) + '::' + getIdentifier(t).name]
1983
1984        statements = []
1985        if len(ignored_warnings) > 0:
1986            statements.append('#![allow(%s)]' % ','.join(ignored_warnings))
1987        statements.extend('use %s;' % i for i in sorted(set(imports + extras)))
1988
1989        CGWrapper.__init__(self, child,
1990                           pre='\n'.join(statements) + '\n\n')
1991
1992
1993class CGIfWrapper(CGWrapper):
1994    def __init__(self, condition, child):
1995        pre = CGWrapper(CGGeneric(condition), pre="if ", post=" {\n",
1996                        reindent=True)
1997        CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(),
1998                           post="\n}")
1999
2000
2001class CGTemplatedType(CGWrapper):
2002    def __init__(self, templateName, child):
2003        CGWrapper.__init__(self, child, pre=templateName + "<", post=">")
2004
2005
2006class CGNamespace(CGWrapper):
2007    def __init__(self, namespace, child, public=False):
2008        pre = "%smod %s {\n" % ("pub " if public else "", namespace)
2009        post = "} // mod %s" % namespace
2010        CGWrapper.__init__(self, child, pre=pre, post=post)
2011
2012    @staticmethod
2013    def build(namespaces, child, public=False):
2014        """
2015        Static helper method to build multiple wrapped namespaces.
2016        """
2017        if not namespaces:
2018            return child
2019        inner = CGNamespace.build(namespaces[1:], child, public=public)
2020        return CGNamespace(namespaces[0], inner, public=public)
2021
2022
2023def DOMClassTypeId(desc):
2024    protochain = desc.prototypeChain
2025    inner = ""
2026    if desc.hasDescendants():
2027        if desc.interface.getExtendedAttribute("Abstract"):
2028            return "::dom::bindings::codegen::InheritTypes::TopTypeId { abstract_: () }"
2029        name = desc.interface.identifier.name
2030        inner = "(::dom::bindings::codegen::InheritTypes::%sTypeId::%s)" % (name, name)
2031    elif len(protochain) == 1:
2032        return "::dom::bindings::codegen::InheritTypes::TopTypeId { alone: () }"
2033    reversed_protochain = list(reversed(protochain))
2034    for (child, parent) in zip(reversed_protochain, reversed_protochain[1:]):
2035        inner = "(::dom::bindings::codegen::InheritTypes::%sTypeId::%s%s)" % (parent, child, inner)
2036    return "::dom::bindings::codegen::InheritTypes::TopTypeId { %s: %s }" % (protochain[0].lower(), inner)
2037
2038
2039def DOMClass(descriptor):
2040    protoList = ['PrototypeList::ID::' + proto for proto in descriptor.prototypeChain]
2041    # Pad out the list to the right length with ID::Last so we
2042    # guarantee that all the lists are the same length.  ID::Last
2043    # is never the ID of any prototype, so it's safe to use as
2044    # padding.
2045    protoList.extend(['PrototypeList::ID::Last'] * (descriptor.config.maxProtoChainLength - len(protoList)))
2046    prototypeChainString = ', '.join(protoList)
2047    mallocSizeOf = 'malloc_size_of_including_raw_self::<%s>' % descriptor.concreteType
2048    if descriptor.isGlobal():
2049        globals_ = camel_to_upper_snake(descriptor.name)
2050    else:
2051        globals_ = 'EMPTY'
2052    return """\
2053DOMClass {
2054    interface_chain: [ %s ],
2055    type_id: %s,
2056    malloc_size_of: %s as unsafe fn(&mut _, _) -> _,
2057    global: InterfaceObjectMap::Globals::%s,
2058}""" % (prototypeChainString, DOMClassTypeId(descriptor), mallocSizeOf, globals_)
2059
2060
2061class CGDOMJSClass(CGThing):
2062    """
2063    Generate a DOMJSClass for a given descriptor
2064    """
2065    def __init__(self, descriptor):
2066        CGThing.__init__(self)
2067        self.descriptor = descriptor
2068
2069    def define(self):
2070        args = {
2071            "domClass": DOMClass(self.descriptor),
2072            "enumerateHook": "None",
2073            "finalizeHook": FINALIZE_HOOK_NAME,
2074            "flags": "0",
2075            "name": str_to_const_array(self.descriptor.interface.identifier.name),
2076            "resolveHook": "None",
2077            "slots": "1",
2078            "traceHook": TRACE_HOOK_NAME,
2079        }
2080        if self.descriptor.isGlobal():
2081            assert not self.descriptor.weakReferenceable
2082            args["enumerateHook"] = "Some(enumerate_global)"
2083            args["flags"] = "JSCLASS_IS_GLOBAL | JSCLASS_DOM_GLOBAL"
2084            args["slots"] = "JSCLASS_GLOBAL_SLOT_COUNT + 1"
2085            args["resolveHook"] = "Some(resolve_global)"
2086            args["traceHook"] = "js::jsapi::JS_GlobalObjectTraceHook"
2087        elif self.descriptor.weakReferenceable:
2088            args["slots"] = "2"
2089        return """\
2090static CLASS_OPS: js::jsapi::JSClassOps = js::jsapi::JSClassOps {
2091    addProperty: None,
2092    delProperty: None,
2093    getProperty: None,
2094    setProperty: None,
2095    enumerate: %(enumerateHook)s,
2096    resolve: %(resolveHook)s,
2097    mayResolve: None,
2098    finalize: Some(%(finalizeHook)s),
2099    call: None,
2100    hasInstance: None,
2101    construct: None,
2102    trace: Some(%(traceHook)s),
2103};
2104
2105static Class: DOMJSClass = DOMJSClass {
2106    base: js::jsapi::JSClass {
2107        name: %(name)s as *const u8 as *const libc::c_char,
2108        flags: JSCLASS_IS_DOMJSCLASS | %(flags)s |
2109               (((%(slots)s) & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT)
2110               /* JSCLASS_HAS_RESERVED_SLOTS(%(slots)s) */,
2111        cOps: &CLASS_OPS,
2112        reserved: [0 as *mut _; 3],
2113    },
2114    dom_class: %(domClass)s
2115};""" % args
2116
2117
2118def str_to_const_array(s):
2119    return "b\"%s\\0\"" % s
2120
2121
2122class CGPrototypeJSClass(CGThing):
2123    def __init__(self, descriptor):
2124        CGThing.__init__(self)
2125        self.descriptor = descriptor
2126
2127    def define(self):
2128        name = str_to_const_array(self.descriptor.interface.identifier.name + "Prototype")
2129        slotCount = 0
2130        if self.descriptor.hasUnforgeableMembers:
2131            slotCount += 1
2132        return """\
2133static PrototypeClass: JSClass = JSClass {
2134    name: %(name)s as *const u8 as *const libc::c_char,
2135    flags:
2136        // JSCLASS_HAS_RESERVED_SLOTS(%(slotCount)s)
2137        (%(slotCount)s & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT,
2138    cOps: 0 as *const _,
2139    reserved: [0 as *mut os::raw::c_void; 3]
2140};
2141""" % {'name': name, 'slotCount': slotCount}
2142
2143
2144class CGInterfaceObjectJSClass(CGThing):
2145    def __init__(self, descriptor):
2146        assert descriptor.interface.hasInterfaceObject() and not descriptor.interface.isCallback()
2147        CGThing.__init__(self)
2148        self.descriptor = descriptor
2149
2150    def define(self):
2151        if self.descriptor.interface.isNamespace():
2152            classString = self.descriptor.interface.getExtendedAttribute("ClassString")
2153            if classString:
2154                classString = classString[0]
2155            else:
2156                classString = "Object"
2157            return """\
2158static NAMESPACE_OBJECT_CLASS: NamespaceObjectClass = unsafe {
2159    NamespaceObjectClass::new(%s)
2160};
2161""" % str_to_const_array(classString)
2162        if self.descriptor.interface.ctor():
2163            constructorBehavior = "InterfaceConstructorBehavior::call(%s)" % CONSTRUCT_HOOK_NAME
2164        else:
2165            constructorBehavior = "InterfaceConstructorBehavior::throw()"
2166        name = self.descriptor.interface.identifier.name
2167        args = {
2168            "constructorBehavior": constructorBehavior,
2169            "id": name,
2170            "representation": 'b"function %s() {\\n    [native code]\\n}"' % name,
2171            "depth": self.descriptor.prototypeDepth
2172        }
2173        return """\
2174static INTERFACE_OBJECT_CLASS: NonCallbackInterfaceObjectClass =
2175    NonCallbackInterfaceObjectClass::new(
2176        &%(constructorBehavior)s,
2177        %(representation)s,
2178        PrototypeList::ID::%(id)s,
2179        %(depth)s);
2180""" % args
2181
2182
2183class CGList(CGThing):
2184    """
2185    Generate code for a list of GCThings.  Just concatenates them together, with
2186    an optional joiner string.  "\n" is a common joiner.
2187    """
2188    def __init__(self, children, joiner=""):
2189        CGThing.__init__(self)
2190        # Make a copy of the kids into a list, because if someone passes in a
2191        # generator we won't be able to both declare and define ourselves, or
2192        # define ourselves more than once!
2193        self.children = list(children)
2194        self.joiner = joiner
2195
2196    def append(self, child):
2197        self.children.append(child)
2198
2199    def prepend(self, child):
2200        self.children.insert(0, child)
2201
2202    def join(self, iterable):
2203        return self.joiner.join(s for s in iterable if len(s) > 0)
2204
2205    def define(self):
2206        return self.join(child.define() for child in self.children if child is not None)
2207
2208    def __len__(self):
2209        return len(self.children)
2210
2211
2212class CGIfElseWrapper(CGList):
2213    def __init__(self, condition, ifTrue, ifFalse):
2214        kids = [CGIfWrapper(condition, ifTrue),
2215                CGWrapper(CGIndenter(ifFalse), pre=" else {\n", post="\n}")]
2216        CGList.__init__(self, kids)
2217
2218
2219class CGGeneric(CGThing):
2220    """
2221    A class that spits out a fixed string into the codegen.  Can spit out a
2222    separate string for the declaration too.
2223    """
2224    def __init__(self, text):
2225        self.text = text
2226
2227    def define(self):
2228        return self.text
2229
2230
2231class CGCallbackTempRoot(CGGeneric):
2232    def __init__(self, name):
2233        CGGeneric.__init__(self, "%s::new(cx, ${val}.get().to_object())" % name)
2234
2235
2236def getAllTypes(descriptors, dictionaries, callbacks, typedefs):
2237    """
2238    Generate all the types we're dealing with.  For each type, a tuple
2239    containing type, descriptor, dictionary is yielded.  The
2240    descriptor and dictionary can be None if the type does not come
2241    from a descriptor or dictionary; they will never both be non-None.
2242    """
2243    for d in descriptors:
2244        for t in getTypesFromDescriptor(d):
2245            yield (t, d, None)
2246    for dictionary in dictionaries:
2247        for t in getTypesFromDictionary(dictionary):
2248            yield (t, None, dictionary)
2249    for callback in callbacks:
2250        for t in getTypesFromCallback(callback):
2251            yield (t, None, None)
2252    for typedef in typedefs:
2253        yield (typedef.innerType, None, None)
2254
2255
2256def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
2257    """
2258    Returns a CGList containing CGUnionStructs for every union.
2259    """
2260
2261    imports = [
2262        'dom',
2263        'dom::bindings::codegen::PrototypeList',
2264        'dom::bindings::conversions::ConversionResult',
2265        'dom::bindings::conversions::FromJSValConvertible',
2266        'dom::bindings::conversions::ToJSValConvertible',
2267        'dom::bindings::conversions::ConversionBehavior',
2268        'dom::bindings::conversions::StringificationBehavior',
2269        'dom::bindings::conversions::root_from_handlevalue',
2270        'dom::bindings::error::throw_not_in_union',
2271        'std::ptr::NonNull',
2272        'dom::bindings::mozmap::MozMap',
2273        'dom::bindings::root::DomRoot',
2274        'dom::bindings::str::ByteString',
2275        'dom::bindings::str::DOMString',
2276        'dom::bindings::str::USVString',
2277        'dom::bindings::trace::RootedTraceableBox',
2278        'dom::types::*',
2279        'js::error::throw_type_error',
2280        'js::jsapi::HandleValue',
2281        'js::jsapi::Heap',
2282        'js::jsapi::JSContext',
2283        'js::jsapi::JSObject',
2284        'js::jsapi::MutableHandleValue',
2285        'js::jsval::JSVal',
2286    ]
2287
2288    # Now find all the things we'll need as arguments and return values because
2289    # we need to wrap or unwrap them.
2290    unionStructs = dict()
2291    for (t, descriptor, dictionary) in getAllTypes(descriptors, dictionaries, callbacks, typedefs):
2292        if dictionary:
2293            imports.append("%s::%s" % (CGDictionary.makeModuleName(dictionary),
2294                                       CGDictionary.makeDictionaryName(dictionary)))
2295        t = t.unroll()
2296        if not t.isUnion():
2297            continue
2298        name = str(t)
2299        if name not in unionStructs:
2300            provider = descriptor or config.getDescriptorProvider()
2301            unionStructs[name] = CGList([
2302                CGUnionStruct(t, provider),
2303                CGUnionConversionStruct(t, provider)
2304            ])
2305
2306    # Sort unionStructs by key, retrieve value
2307    unionStructs = (i[1] for i in sorted(unionStructs.items(), key=operator.itemgetter(0)))
2308
2309    return CGImports(CGList(unionStructs, "\n\n"),
2310                     descriptors=[],
2311                     callbacks=[],
2312                     dictionaries=[],
2313                     enums=[],
2314                     typedefs=[],
2315                     imports=imports,
2316                     config=config,
2317                     ignored_warnings=[])
2318
2319
2320class Argument():
2321    """
2322    A class for outputting the type and name of an argument
2323    """
2324    def __init__(self, argType, name, default=None, mutable=False):
2325        self.argType = argType
2326        self.name = name
2327        self.default = default
2328        self.mutable = mutable
2329
2330    def declare(self):
2331        string = ('mut ' if self.mutable else '') + self.name + ((': ' + self.argType) if self.argType else '')
2332        # XXXjdm Support default arguments somehow :/
2333        # if self.default is not None:
2334        #     string += " = " + self.default
2335        return string
2336
2337    def define(self):
2338        return self.argType + ' ' + self.name
2339
2340
2341class CGAbstractMethod(CGThing):
2342    """
2343    An abstract class for generating code for a method.  Subclasses
2344    should override definition_body to create the actual code.
2345
2346    descriptor is the descriptor for the interface the method is associated with
2347
2348    name is the name of the method as a string
2349
2350    returnType is the IDLType of the return value
2351
2352    args is a list of Argument objects
2353
2354    inline should be True to generate an inline method, whose body is
2355    part of the declaration.
2356
2357    alwaysInline should be True to generate an inline method annotated with
2358    MOZ_ALWAYS_INLINE.
2359
2360    If templateArgs is not None it should be a list of strings containing
2361    template arguments, and the function will be templatized using those
2362    arguments.
2363
2364    docs is None or documentation for the method in a string.
2365
2366    unsafe is used to add the decorator 'unsafe' to a function, giving as a result
2367    an 'unsafe fn()' declaration.
2368    """
2369    def __init__(self, descriptor, name, returnType, args, inline=False,
2370                 alwaysInline=False, extern=False, unsafe=False, pub=False,
2371                 templateArgs=None, docs=None, doesNotPanic=False):
2372        CGThing.__init__(self)
2373        self.descriptor = descriptor
2374        self.name = name
2375        self.returnType = returnType
2376        self.args = args
2377        self.alwaysInline = alwaysInline
2378        self.extern = extern
2379        self.unsafe = extern or unsafe
2380        self.templateArgs = templateArgs
2381        self.pub = pub
2382        self.docs = docs
2383        self.catchPanic = self.extern and not doesNotPanic
2384
2385    def _argstring(self):
2386        return ', '.join([a.declare() for a in self.args])
2387
2388    def _template(self):
2389        if self.templateArgs is None:
2390            return ''
2391        return '<%s>\n' % ', '.join(self.templateArgs)
2392
2393    def _docs(self):
2394        if self.docs is None:
2395            return ''
2396
2397        lines = self.docs.splitlines()
2398        return ''.join('/// %s\n' % line for line in lines)
2399
2400    def _decorators(self):
2401        decorators = []
2402        if self.alwaysInline:
2403            decorators.append('#[inline]')
2404
2405        if self.pub:
2406            decorators.append('pub')
2407
2408        if self.unsafe:
2409            decorators.append('unsafe')
2410
2411        if self.extern:
2412            decorators.append('extern')
2413
2414        if not decorators:
2415            return ''
2416        return ' '.join(decorators) + ' '
2417
2418    def _returnType(self):
2419        return (" -> %s" % self.returnType) if self.returnType != "void" else ""
2420
2421    def define(self):
2422        body = self.definition_body()
2423
2424        if self.catchPanic:
2425            body = CGWrapper(CGIndenter(body),
2426                             pre="return wrap_panic(panic::AssertUnwindSafe(|| {\n",
2427                             post=("""\n}), %s);""" % ("()" if self.returnType == "void" else "false")))
2428
2429        return CGWrapper(CGIndenter(body),
2430                         pre=self.definition_prologue(),
2431                         post=self.definition_epilogue()).define()
2432
2433    def definition_prologue(self):
2434        return "%s%sfn %s%s(%s)%s {\n" % (self._docs(), self._decorators(),
2435                                          self.name, self._template(),
2436                                          self._argstring(), self._returnType())
2437
2438    def definition_epilogue(self):
2439        return "\n}\n"
2440
2441    def definition_body(self):
2442        raise NotImplementedError  # Override me!
2443
2444
2445class CGConstructorEnabled(CGAbstractMethod):
2446    """
2447    A method for testing whether we should be exposing this interface object.
2448    This can perform various tests depending on what conditions are specified
2449    on the interface.
2450    """
2451    def __init__(self, descriptor):
2452        CGAbstractMethod.__init__(self, descriptor,
2453                                  'ConstructorEnabled', 'bool',
2454                                  [Argument("*mut JSContext", "aCx"),
2455                                   Argument("HandleObject", "aObj")],
2456                                  unsafe=True)
2457
2458    def definition_body(self):
2459        conditions = []
2460        iface = self.descriptor.interface
2461
2462        bits = " | ".join(sorted(
2463            "InterfaceObjectMap::Globals::" + camel_to_upper_snake(i) for i in iface.exposureSet
2464        ))
2465        conditions.append("is_exposed_in(aObj, %s)" % bits)
2466
2467        pref = iface.getExtendedAttribute("Pref")
2468        if pref:
2469            assert isinstance(pref, list) and len(pref) == 1
2470            conditions.append('PREFS.get("%s").as_boolean().unwrap_or(false)' % pref[0])
2471
2472        func = iface.getExtendedAttribute("Func")
2473        if func:
2474            assert isinstance(func, list) and len(func) == 1
2475            conditions.append("%s(aCx, aObj)" % func[0])
2476
2477        return CGList((CGGeneric(cond) for cond in conditions), " &&\n")
2478
2479
2480def CreateBindingJSObject(descriptor, parent=None):
2481    assert not descriptor.isGlobal()
2482    create = "let raw = Box::into_raw(object);\nlet _rt = RootedTraceable::new(&*raw);\n"
2483    if descriptor.proxy:
2484        create += """
2485let handler = RegisterBindings::PROXY_HANDLERS[PrototypeList::Proxies::%s as usize];
2486rooted!(in(cx) let private = PrivateValue(raw as *const libc::c_void));
2487let obj = NewProxyObject(cx, handler,
2488                         private.handle(),
2489                         proto.get(), %s.get(),
2490                         ptr::null_mut(), ptr::null_mut());
2491assert!(!obj.is_null());
2492rooted!(in(cx) let obj = obj);\
2493""" % (descriptor.name, parent)
2494    else:
2495        create += ("rooted!(in(cx) let obj = JS_NewObjectWithGivenProto(\n"
2496                   "    cx, &Class.base as *const JSClass, proto.handle()));\n"
2497                   "assert!(!obj.is_null());\n"
2498                   "\n"
2499                   "JS_SetReservedSlot(obj.get(), DOM_OBJECT_SLOT,\n"
2500                   "                   PrivateValue(raw as *const libc::c_void));")
2501    if descriptor.weakReferenceable:
2502        create += """
2503JS_SetReservedSlot(obj.get(), DOM_WEAK_SLOT, PrivateValue(ptr::null()));"""
2504    return create
2505
2506
2507def InitUnforgeablePropertiesOnHolder(descriptor, properties):
2508    """
2509    Define the unforgeable properties on the unforgeable holder for
2510    the interface represented by descriptor.
2511
2512    properties is a PropertyArrays instance.
2513    """
2514    unforgeables = []
2515
2516    defineUnforgeableAttrs = "define_guarded_properties(cx, unforgeable_holder.handle(), %s);"
2517    defineUnforgeableMethods = "define_guarded_methods(cx, unforgeable_holder.handle(), %s);"
2518
2519    unforgeableMembers = [
2520        (defineUnforgeableAttrs, properties.unforgeable_attrs),
2521        (defineUnforgeableMethods, properties.unforgeable_methods),
2522    ]
2523    for template, array in unforgeableMembers:
2524        if array.length() > 0:
2525            unforgeables.append(CGGeneric(template % array.variableName()))
2526    return CGList(unforgeables, "\n")
2527
2528
2529def CopyUnforgeablePropertiesToInstance(descriptor):
2530    """
2531    Copy the unforgeable properties from the unforgeable holder for
2532    this interface to the instance object we have.
2533    """
2534    if not descriptor.hasUnforgeableMembers:
2535        return ""
2536    copyCode = ""
2537
2538    # For proxies, we want to define on the expando object, not directly on the
2539    # reflector, so we can make sure we don't get confused by named getters.
2540    if descriptor.proxy:
2541        copyCode += """\
2542rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
2543ensure_expando_object(cx, obj.handle(), expando.handle_mut());
2544"""
2545        obj = "expando"
2546    else:
2547        obj = "obj"
2548
2549    # We can't do the fast copy for globals, because we can't allocate the
2550    # unforgeable holder for those with the right JSClass. Luckily, there
2551    # aren't too many globals being created.
2552    if descriptor.isGlobal():
2553        copyFunc = "JS_CopyPropertiesFrom"
2554    else:
2555        copyFunc = "JS_InitializePropertiesFromCompatibleNativeObject"
2556    copyCode += """\
2557rooted!(in(cx) let mut unforgeable_holder = ptr::null_mut::<JSObject>());
2558unforgeable_holder.handle_mut().set(
2559    JS_GetReservedSlot(proto.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT).to_object());
2560assert!(%(copyFunc)s(cx, %(obj)s.handle(), unforgeable_holder.handle()));
2561""" % {'copyFunc': copyFunc, 'obj': obj}
2562
2563    return copyCode
2564
2565
2566class CGWrapMethod(CGAbstractMethod):
2567    """
2568    Class that generates the FooBinding::Wrap function for non-callback
2569    interfaces.
2570    """
2571    def __init__(self, descriptor):
2572        assert not descriptor.interface.isCallback()
2573        assert not descriptor.isGlobal()
2574        args = [Argument('*mut JSContext', 'cx'),
2575                Argument('&GlobalScope', 'scope'),
2576                Argument("Box<%s>" % descriptor.concreteType, 'object')]
2577        retval = 'DomRoot<%s>' % descriptor.concreteType
2578        CGAbstractMethod.__init__(self, descriptor, 'Wrap', retval, args,
2579                                  pub=True, unsafe=True)
2580
2581    def definition_body(self):
2582        unforgeable = CopyUnforgeablePropertiesToInstance(self.descriptor)
2583        create = CreateBindingJSObject(self.descriptor, "scope")
2584        return CGGeneric("""\
2585let scope = scope.reflector().get_jsobject();
2586assert!(!scope.get().is_null());
2587assert!(((*get_object_class(scope.get())).flags & JSCLASS_IS_GLOBAL) != 0);
2588
2589rooted!(in(cx) let mut proto = ptr::null_mut::<JSObject>());
2590let _ac = JSAutoCompartment::new(cx, scope.get());
2591GetProtoObject(cx, scope, proto.handle_mut());
2592assert!(!proto.is_null());
2593
2594%(createObject)s
2595
2596%(copyUnforgeable)s
2597(*raw).init_reflector(obj.get());
2598
2599DomRoot::from_ref(&*raw)""" % {'copyUnforgeable': unforgeable, 'createObject': create})
2600
2601
2602class CGWrapGlobalMethod(CGAbstractMethod):
2603    """
2604    Class that generates the FooBinding::Wrap function for global interfaces.
2605    """
2606    def __init__(self, descriptor, properties):
2607        assert not descriptor.interface.isCallback()
2608        assert descriptor.isGlobal()
2609        args = [Argument('*mut JSContext', 'cx'),
2610                Argument("Box<%s>" % descriptor.concreteType, 'object')]
2611        retval = 'DomRoot<%s>' % descriptor.concreteType
2612        CGAbstractMethod.__init__(self, descriptor, 'Wrap', retval, args,
2613                                  pub=True, unsafe=True)
2614        self.properties = properties
2615
2616    def definition_body(self):
2617        values = {
2618            "unforgeable": CopyUnforgeablePropertiesToInstance(self.descriptor)
2619        }
2620
2621        pairs = [
2622            ("define_guarded_properties", self.properties.attrs),
2623            ("define_guarded_methods", self.properties.methods),
2624            ("define_guarded_constants", self.properties.consts)
2625        ]
2626        members = ["%s(cx, obj.handle(), %s);" % (function, array.variableName())
2627                   for (function, array) in pairs if array.length() > 0]
2628        values["members"] = "\n".join(members)
2629
2630        return CGGeneric("""\
2631let raw = Box::into_raw(object);
2632let _rt = RootedTraceable::new(&*raw);
2633
2634rooted!(in(cx) let mut obj = ptr::null_mut::<JSObject>());
2635create_global_object(
2636    cx,
2637    &Class.base,
2638    raw as *const libc::c_void,
2639    _trace,
2640    obj.handle_mut());
2641assert!(!obj.is_null());
2642
2643(*raw).init_reflector(obj.get());
2644
2645let _ac = JSAutoCompartment::new(cx, obj.get());
2646rooted!(in(cx) let mut proto = ptr::null_mut::<JSObject>());
2647GetProtoObject(cx, obj.handle(), proto.handle_mut());
2648assert!(JS_SplicePrototype(cx, obj.handle(), proto.handle()));
2649let mut immutable = false;
2650assert!(JS_SetImmutablePrototype(cx, obj.handle(), &mut immutable));
2651assert!(immutable);
2652
2653%(members)s
2654
2655%(unforgeable)s
2656
2657DomRoot::from_ref(&*raw)\
2658""" % values)
2659
2660
2661class CGIDLInterface(CGThing):
2662    """
2663    Class for codegen of an implementation of the IDLInterface trait.
2664    """
2665    def __init__(self, descriptor):
2666        CGThing.__init__(self)
2667        self.descriptor = descriptor
2668
2669    def define(self):
2670        interface = self.descriptor.interface
2671        name = self.descriptor.concreteType
2672        if (interface.getUserData("hasConcreteDescendant", False) or
2673                interface.getUserData("hasProxyDescendant", False)):
2674            depth = self.descriptor.prototypeDepth
2675            check = "class.interface_chain[%s] == PrototypeList::ID::%s" % (depth, name)
2676        elif self.descriptor.proxy:
2677            check = "class as *const _ == &Class as *const _"
2678        else:
2679            check = "class as *const _ == &Class.dom_class as *const _"
2680        return """\
2681impl IDLInterface for %(name)s {
2682    #[inline]
2683    fn derives(class: &'static DOMClass) -> bool {
2684        %(check)s
2685    }
2686}
2687
2688impl PartialEq for %(name)s {
2689    fn eq(&self, other: &%(name)s) -> bool {
2690        self as *const %(name)s == &*other
2691    }
2692}
2693""" % {'check': check, 'name': name}
2694
2695
2696class CGAbstractExternMethod(CGAbstractMethod):
2697    """
2698    Abstract base class for codegen of implementation-only (no
2699    declaration) static methods.
2700    """
2701    def __init__(self, descriptor, name, returnType, args, doesNotPanic=False):
2702        CGAbstractMethod.__init__(self, descriptor, name, returnType, args,
2703                                  inline=False, extern=True, doesNotPanic=doesNotPanic)
2704
2705
2706class PropertyArrays():
2707    def __init__(self, descriptor):
2708        self.static_methods = MethodDefiner(descriptor, "StaticMethods",
2709                                            static=True, unforgeable=False)
2710        self.static_attrs = AttrDefiner(descriptor, "StaticAttributes",
2711                                        static=True, unforgeable=False)
2712        self.methods = MethodDefiner(descriptor, "Methods", static=False, unforgeable=False)
2713        self.unforgeable_methods = MethodDefiner(descriptor, "UnforgeableMethods",
2714                                                 static=False, unforgeable=True)
2715        self.attrs = AttrDefiner(descriptor, "Attributes", static=False, unforgeable=False)
2716        self.unforgeable_attrs = AttrDefiner(descriptor, "UnforgeableAttributes",
2717                                             static=False, unforgeable=True)
2718        self.consts = ConstDefiner(descriptor, "Constants")
2719        pass
2720
2721    @staticmethod
2722    def arrayNames():
2723        return [
2724            "static_methods",
2725            "static_attrs",
2726            "methods",
2727            "unforgeable_methods",
2728            "attrs",
2729            "unforgeable_attrs",
2730            "consts",
2731        ]
2732
2733    def variableNames(self):
2734        names = {}
2735        for array in self.arrayNames():
2736            names[array] = getattr(self, array).variableName()
2737        return names
2738
2739    def __str__(self):
2740        define = ""
2741        for array in self.arrayNames():
2742            define += str(getattr(self, array))
2743        return define
2744
2745
2746class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
2747    """
2748    Generate the CreateInterfaceObjects method for an interface descriptor.
2749
2750    properties should be a PropertyArrays instance.
2751    """
2752    def __init__(self, descriptor, properties, haveUnscopables):
2753        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'global'),
2754                Argument('*mut ProtoOrIfaceArray', 'cache')]
2755        CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args,
2756                                  unsafe=True)
2757        self.properties = properties
2758        self.haveUnscopables = haveUnscopables
2759
2760    def definition_body(self):
2761        name = self.descriptor.interface.identifier.name
2762        if self.descriptor.interface.isNamespace():
2763            if self.descriptor.interface.getExtendedAttribute("ProtoObjectHack"):
2764                proto = "JS_GetObjectPrototype(cx, global)"
2765            else:
2766                proto = "JS_NewPlainObject(cx)"
2767            if self.properties.static_methods.length():
2768                methods = self.properties.static_methods.variableName()
2769            else:
2770                methods = "&[]"
2771            return CGGeneric("""\
2772rooted!(in(cx) let proto = %(proto)s);
2773assert!(!proto.is_null());
2774rooted!(in(cx) let mut namespace = ptr::null_mut::<JSObject>());
2775create_namespace_object(cx, global, proto.handle(), &NAMESPACE_OBJECT_CLASS,
2776                        %(methods)s, %(name)s, namespace.handle_mut());
2777assert!(!namespace.is_null());
2778assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
2779(*cache)[PrototypeList::Constructor::%(id)s as usize] = namespace.get();
2780<*mut JSObject>::post_barrier((*cache).as_mut_ptr().offset(PrototypeList::Constructor::%(id)s as isize),
2781                              ptr::null_mut(),
2782                              namespace.get());
2783""" % {"id": MakeNativeName(name), "methods": methods, "name": str_to_const_array(name), "proto": proto})
2784        if self.descriptor.interface.isCallback():
2785            assert not self.descriptor.interface.ctor() and self.descriptor.interface.hasConstants()
2786            return CGGeneric("""\
2787rooted!(in(cx) let mut interface = ptr::null_mut::<JSObject>());
2788create_callback_interface_object(cx, global, sConstants, %(name)s, interface.handle_mut());
2789assert!(!interface.is_null());
2790assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
2791(*cache)[PrototypeList::Constructor::%(id)s as usize] = interface.get();
2792<*mut JSObject>::post_barrier((*cache).as_mut_ptr().offset(PrototypeList::Constructor::%(id)s as isize),
2793                              ptr::null_mut(),
2794                              interface.get());
2795""" % {"id": name, "name": str_to_const_array(name)})
2796
2797        parentName = self.descriptor.getParentName()
2798        if not parentName:
2799            if self.descriptor.interface.getExtendedAttribute("ExceptionClass"):
2800                getPrototypeProto = "prototype_proto.set(JS_GetErrorPrototype(cx))"
2801            elif self.descriptor.interface.isIteratorInterface():
2802                getPrototypeProto = "prototype_proto.set(JS_GetIteratorPrototype(cx))"
2803            else:
2804                getPrototypeProto = "prototype_proto.set(JS_GetObjectPrototype(cx, global))"
2805        else:
2806            getPrototypeProto = ("%s::GetProtoObject(cx, global, prototype_proto.handle_mut())" %
2807                                 toBindingNamespace(parentName))
2808
2809        code = [CGGeneric("""\
2810rooted!(in(cx) let mut prototype_proto = ptr::null_mut::<JSObject>());
2811%s;
2812assert!(!prototype_proto.is_null());""" % getPrototypeProto)]
2813
2814        properties = {
2815            "id": name,
2816            "unscopables": "unscopable_names" if self.haveUnscopables else "&[]"
2817        }
2818        for arrayName in self.properties.arrayNames():
2819            array = getattr(self.properties, arrayName)
2820            if array.length():
2821                properties[arrayName] = array.variableName()
2822            else:
2823                properties[arrayName] = "&[]"
2824
2825        if self.descriptor.isGlobal():
2826            assert not self.haveUnscopables
2827            proto_properties = {
2828                "attrs": "&[]",
2829                "consts": "&[]",
2830                "id": name,
2831                "methods": "&[]",
2832                "unscopables": "&[]",
2833            }
2834        else:
2835            proto_properties = properties
2836
2837        code.append(CGGeneric("""
2838rooted!(in(cx) let mut prototype = ptr::null_mut::<JSObject>());
2839create_interface_prototype_object(cx,
2840                                  prototype_proto.handle(),
2841                                  &PrototypeClass,
2842                                  %(methods)s,
2843                                  %(attrs)s,
2844                                  %(consts)s,
2845                                  %(unscopables)s,
2846                                  prototype.handle_mut());
2847assert!(!prototype.is_null());
2848assert!((*cache)[PrototypeList::ID::%(id)s as usize].is_null());
2849(*cache)[PrototypeList::ID::%(id)s as usize] = prototype.get();
2850<*mut JSObject>::post_barrier((*cache).as_mut_ptr().offset(PrototypeList::ID::%(id)s as isize),
2851                              ptr::null_mut(),
2852                              prototype.get());
2853""" % proto_properties))
2854
2855        if self.descriptor.interface.hasInterfaceObject():
2856            properties["name"] = str_to_const_array(name)
2857            if self.descriptor.interface.ctor():
2858                properties["length"] = methodLength(self.descriptor.interface.ctor())
2859            else:
2860                properties["length"] = 0
2861            parentName = self.descriptor.getParentName()
2862            if parentName:
2863                parentName = toBindingNamespace(parentName)
2864                code.append(CGGeneric("""
2865rooted!(in(cx) let mut interface_proto = ptr::null_mut::<JSObject>());
2866%s::GetConstructorObject(cx, global, interface_proto.handle_mut());""" % parentName))
2867            else:
2868                code.append(CGGeneric("""
2869rooted!(in(cx) let interface_proto = JS_GetFunctionPrototype(cx, global));"""))
2870            code.append(CGGeneric("""\
2871assert!(!interface_proto.is_null());
2872
2873rooted!(in(cx) let mut interface = ptr::null_mut::<JSObject>());
2874create_noncallback_interface_object(cx,
2875                                    global,
2876                                    interface_proto.handle(),
2877                                    &INTERFACE_OBJECT_CLASS,
2878                                    %(static_methods)s,
2879                                    %(static_attrs)s,
2880                                    %(consts)s,
2881                                    prototype.handle(),
2882                                    %(name)s,
2883                                    %(length)s,
2884                                    interface.handle_mut());
2885assert!(!interface.is_null());""" % properties))
2886            if self.descriptor.shouldCacheConstructor():
2887                code.append(CGGeneric("""\
2888assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
2889(*cache)[PrototypeList::Constructor::%(id)s as usize] = interface.get();
2890<*mut JSObject>::post_barrier((*cache).as_mut_ptr().offset(PrototypeList::Constructor::%(id)s as isize),
2891                              ptr::null_mut(),
2892                              interface.get());
2893""" % properties))
2894
2895        aliasedMembers = [m for m in self.descriptor.interface.members if m.isMethod() and m.aliases]
2896        if aliasedMembers:
2897            def defineAlias(alias):
2898                if alias == "@@iterator":
2899                    symbolJSID = "RUST_SYMBOL_TO_JSID(GetWellKnownSymbol(cx, SymbolCode::iterator))"
2900                    getSymbolJSID = CGGeneric(fill("rooted!(in(cx) let iteratorId = ${symbolJSID});",
2901                                                   symbolJSID=symbolJSID))
2902                    defineFn = "JS_DefinePropertyById2"
2903                    prop = "iteratorId.handle()"
2904                elif alias.startswith("@@"):
2905                    raise TypeError("Can't handle any well-known Symbol other than @@iterator")
2906                else:
2907                    getSymbolJSID = None
2908                    defineFn = "JS_DefineProperty"
2909                    prop = '"%s"' % alias
2910                return CGList([
2911                    getSymbolJSID,
2912                    # XXX If we ever create non-enumerable properties that can
2913                    #     be aliased, we should consider making the aliases
2914                    #     match the enumerability of the property being aliased.
2915                    CGGeneric(fill(
2916                        """
2917                        assert!(${defineFn}(cx, prototype.handle(), ${prop}, aliasedVal.handle(),
2918                                            JSPROP_ENUMERATE, None, None));
2919                        """,
2920                        defineFn=defineFn,
2921                        prop=prop))
2922                ], "\n")
2923
2924            def defineAliasesFor(m):
2925                return CGList([
2926                    CGGeneric(fill(
2927                        """
2928                        assert!(JS_GetProperty(cx, prototype.handle(),
2929                                               ${prop} as *const u8 as *const _,
2930                                               aliasedVal.handle_mut()));
2931                        """,
2932                        prop=str_to_const_array(m.identifier.name)))
2933                ] + [defineAlias(alias) for alias in sorted(m.aliases)])
2934
2935            defineAliases = CGList([
2936                CGGeneric(fill("""
2937                    // Set up aliases on the interface prototype object we just created.
2938
2939                    """)),
2940                CGGeneric("rooted!(in(cx) let mut aliasedVal = UndefinedValue());\n\n")
2941            ] + [defineAliasesFor(m) for m in sorted(aliasedMembers)])
2942            code.append(defineAliases)
2943
2944        constructors = self.descriptor.interface.namedConstructors
2945        if constructors:
2946            decl = "let named_constructors: [(ConstructorClassHook, &'static [u8], u32); %d]" % len(constructors)
2947            specs = []
2948            for constructor in constructors:
2949                hook = CONSTRUCT_HOOK_NAME + "_" + constructor.identifier.name
2950                name = str_to_const_array(constructor.identifier.name)
2951                length = methodLength(constructor)
2952                specs.append(CGGeneric("(%s as ConstructorClassHook, %s, %d)" % (hook, name, length)))
2953            values = CGIndenter(CGList(specs, "\n"), 4)
2954            code.append(CGWrapper(values, pre="%s = [\n" % decl, post="\n];"))
2955            code.append(CGGeneric("create_named_constructors(cx, global, &named_constructors, prototype.handle());"))
2956
2957        if self.descriptor.hasUnforgeableMembers:
2958            # We want to use the same JSClass and prototype as the object we'll
2959            # end up defining the unforgeable properties on in the end, so that
2960            # we can use JS_InitializePropertiesFromCompatibleNativeObject to do
2961            # a fast copy.  In the case of proxies that's null, because the
2962            # expando object is a vanilla object, but in the case of other DOM
2963            # objects it's whatever our class is.
2964            #
2965            # Also, for a global we can't use the global's class; just use
2966            # nullpr and when we do the copy off the holder we'll take a slower
2967            # path.  This also means that we don't need to worry about matching
2968            # the prototype.
2969            if self.descriptor.proxy or self.descriptor.isGlobal():
2970                holderClass = "ptr::null()"
2971                holderProto = "HandleObject::null()"
2972            else:
2973                holderClass = "&Class.base as *const JSClass"
2974                holderProto = "prototype.handle()"
2975            code.append(CGGeneric("""
2976rooted!(in(cx) let mut unforgeable_holder = ptr::null_mut::<JSObject>());
2977unforgeable_holder.handle_mut().set(
2978    JS_NewObjectWithoutMetadata(cx, %(holderClass)s, %(holderProto)s));
2979assert!(!unforgeable_holder.is_null());
2980""" % {'holderClass': holderClass, 'holderProto': holderProto}))
2981            code.append(InitUnforgeablePropertiesOnHolder(self.descriptor, self.properties))
2982            code.append(CGGeneric("""\
2983JS_SetReservedSlot(prototype.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT,
2984                   ObjectValue(unforgeable_holder.get()))"""))
2985
2986        return CGList(code, "\n")
2987
2988
2989class CGGetPerInterfaceObject(CGAbstractMethod):
2990    """
2991    A method for getting a per-interface object (a prototype object or interface
2992    constructor object).
2993    """
2994    def __init__(self, descriptor, name, idPrefix="", pub=False):
2995        args = [Argument('*mut JSContext', 'cx'),
2996                Argument('HandleObject', 'global'),
2997                Argument('MutableHandleObject', 'rval')]
2998        CGAbstractMethod.__init__(self, descriptor, name,
2999                                  'void', args, pub=pub, unsafe=True)
3000        self.id = idPrefix + "::" + MakeNativeName(self.descriptor.name)
3001
3002    def definition_body(self):
3003        return CGGeneric("""
3004assert!(((*get_object_class(global.get())).flags & JSCLASS_DOM_GLOBAL) != 0);
3005
3006/* Check to see whether the interface objects are already installed */
3007let proto_or_iface_array = get_proto_or_iface_array(global.get());
3008rval.set((*proto_or_iface_array)[%(id)s as usize]);
3009if !rval.get().is_null() {
3010    return;
3011}
3012
3013CreateInterfaceObjects(cx, global, proto_or_iface_array);
3014rval.set((*proto_or_iface_array)[%(id)s as usize]);
3015assert!(!rval.get().is_null());
3016""" % {"id": self.id})
3017
3018
3019class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
3020    """
3021    A method for getting the interface prototype object.
3022    """
3023    def __init__(self, descriptor):
3024        CGGetPerInterfaceObject.__init__(self, descriptor, "GetProtoObject",
3025                                         "PrototypeList::ID", pub=True)
3026
3027    def definition_body(self):
3028        return CGList([
3029            CGGeneric("""\
3030/* Get the interface prototype object for this class.  This will create the
3031   object as needed. */"""),
3032            CGGetPerInterfaceObject.definition_body(self),
3033        ])
3034
3035
3036class CGGetConstructorObjectMethod(CGGetPerInterfaceObject):
3037    """
3038    A method for getting the interface constructor object.
3039    """
3040    def __init__(self, descriptor):
3041        CGGetPerInterfaceObject.__init__(self, descriptor, "GetConstructorObject",
3042                                         "PrototypeList::Constructor",
3043                                         pub=True)
3044
3045    def definition_body(self):
3046        return CGList([
3047            CGGeneric("""\
3048/* Get the interface object for this class.  This will create the object as
3049   needed. */"""),
3050            CGGetPerInterfaceObject.definition_body(self),
3051        ])
3052
3053
3054class CGDefineProxyHandler(CGAbstractMethod):
3055    """
3056    A method to create and cache the proxy trap for a given interface.
3057    """
3058    def __init__(self, descriptor):
3059        assert descriptor.proxy
3060        CGAbstractMethod.__init__(self, descriptor, 'DefineProxyHandler',
3061                                  '*const libc::c_void', [],
3062                                  pub=True, unsafe=True)
3063
3064    def define(self):
3065        return CGAbstractMethod.define(self)
3066
3067    def definition_body(self):
3068        customDefineProperty = 'proxyhandler::define_property'
3069        if self.descriptor.operations['IndexedSetter'] or self.descriptor.operations['NamedSetter']:
3070            customDefineProperty = 'defineProperty'
3071
3072        customDelete = 'proxyhandler::delete'
3073        if self.descriptor.operations['NamedDeleter']:
3074            customDelete = 'delete'
3075
3076        getOwnEnumerablePropertyKeys = "own_property_keys"
3077        if self.descriptor.interface.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
3078            getOwnEnumerablePropertyKeys = "getOwnEnumerablePropertyKeys"
3079
3080        args = {
3081            "defineProperty": customDefineProperty,
3082            "delete": customDelete,
3083            "getOwnEnumerablePropertyKeys": getOwnEnumerablePropertyKeys,
3084            "trace": TRACE_HOOK_NAME,
3085            "finalize": FINALIZE_HOOK_NAME,
3086        }
3087
3088        return CGGeneric("""\
3089let traps = ProxyTraps {
3090    enter: None,
3091    getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor),
3092    defineProperty: Some(%(defineProperty)s),
3093    ownPropertyKeys: Some(own_property_keys),
3094    delete_: Some(%(delete)s),
3095    enumerate: None,
3096    getPrototypeIfOrdinary: Some(proxyhandler::get_prototype_if_ordinary),
3097    preventExtensions: Some(proxyhandler::prevent_extensions),
3098    isExtensible: Some(proxyhandler::is_extensible),
3099    has: None,
3100    get: Some(get),
3101    set: None,
3102    call: None,
3103    construct: None,
3104    getPropertyDescriptor: Some(get_property_descriptor),
3105    hasOwn: Some(hasOwn),
3106    getOwnEnumerablePropertyKeys: Some(%(getOwnEnumerablePropertyKeys)s),
3107    nativeCall: None,
3108    hasInstance: None,
3109    objectClassIs: None,
3110    className: Some(className),
3111    fun_toString: None,
3112    boxedValue_unbox: None,
3113    defaultValue: None,
3114    trace: Some(%(trace)s),
3115    finalize: Some(%(finalize)s),
3116    objectMoved: None,
3117    isCallable: None,
3118    isConstructor: None,
3119};
3120
3121CreateProxyHandler(&traps, Class.as_void_ptr())\
3122""" % args)
3123
3124
3125class CGDefineDOMInterfaceMethod(CGAbstractMethod):
3126    """
3127    A method for resolve hooks to try to lazily define the interface object for
3128    a given interface.
3129    """
3130    def __init__(self, descriptor):
3131        assert descriptor.interface.hasInterfaceObject()
3132        args = [
3133            Argument('*mut JSContext', 'cx'),
3134            Argument('HandleObject', 'global'),
3135        ]
3136        CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface',
3137                                  'void', args, pub=True, unsafe=True)
3138
3139    def define(self):
3140        return CGAbstractMethod.define(self)
3141
3142    def definition_body(self):
3143        if self.descriptor.interface.isCallback() or self.descriptor.interface.isNamespace():
3144            function = "GetConstructorObject"
3145        else:
3146            function = "GetProtoObject"
3147        return CGGeneric("""\
3148assert!(!global.get().is_null());
3149
3150if !ConstructorEnabled(cx, global) {
3151    return;
3152}
3153
3154rooted!(in(cx) let mut proto = ptr::null_mut::<JSObject>());
3155%s(cx, global, proto.handle_mut());
3156assert!(!proto.is_null());""" % (function,))
3157
3158
3159def needCx(returnType, arguments, considerTypes):
3160    return (considerTypes and
3161            (typeNeedsCx(returnType, True) or
3162             any(typeNeedsCx(a.type) for a in arguments)))
3163
3164
3165class CGCallGenerator(CGThing):
3166    """
3167    A class to generate an actual call to a C++ object.  Assumes that the C++
3168    object is stored in a variable whose name is given by the |object| argument.
3169
3170    errorResult should be a string for the value to return in case of an
3171    exception from the native code, or None if no error reporting is needed.
3172    """
3173    def __init__(self, errorResult, arguments, argsPre, returnType,
3174                 extendedAttributes, descriptor, nativeMethodName,
3175                 static, object="this", hasCEReactions=False):
3176        CGThing.__init__(self)
3177
3178        assert errorResult is None or isinstance(errorResult, str)
3179
3180        isFallible = errorResult is not None
3181
3182        result = getRetvalDeclarationForType(returnType, descriptor)
3183        if isFallible:
3184            result = CGWrapper(result, pre="Result<", post=", Error>")
3185
3186        args = CGList([CGGeneric(arg) for arg in argsPre], ", ")
3187        for (a, name) in arguments:
3188            # XXXjdm Perhaps we should pass all nontrivial types by borrowed pointer
3189            if a.type.isDictionary() and not type_needs_tracing(a.type):
3190                name = "&" + name
3191            args.append(CGGeneric(name))
3192
3193        needsCx = needCx(returnType, (a for (a, _) in arguments), True)
3194
3195        if "cx" not in argsPre and needsCx:
3196            args.prepend(CGGeneric("cx"))
3197
3198        # Build up our actual call
3199        self.cgRoot = CGList([], "\n")
3200
3201        call = CGGeneric(nativeMethodName)
3202        if static:
3203            call = CGWrapper(call, pre="%s::" % MakeNativeName(descriptor.interface.identifier.name))
3204        else:
3205            call = CGWrapper(call, pre="%s." % object)
3206        call = CGList([call, CGWrapper(args, pre="(", post=")")])
3207
3208        if hasCEReactions:
3209            self.cgRoot.append(CGGeneric("push_new_element_queue();\n"))
3210
3211        self.cgRoot.append(CGList([
3212            CGGeneric("let result: "),
3213            result,
3214            CGGeneric(" = "),
3215            call,
3216            CGGeneric(";"),
3217        ]))
3218
3219        if hasCEReactions:
3220            self.cgRoot.append(CGGeneric("pop_current_element_queue();\n"))
3221
3222        if isFallible:
3223            if static:
3224                glob = "global.upcast::<GlobalScope>()"
3225            else:
3226                glob = "&this.global()"
3227
3228            self.cgRoot.append(CGGeneric(
3229                "let result = match result {\n"
3230                "    Ok(result) => result,\n"
3231                "    Err(e) => {\n"
3232                "        throw_dom_exception(cx, %s, e);\n"
3233                "        return%s;\n"
3234                "    },\n"
3235                "};" % (glob, errorResult)))
3236
3237    def define(self):
3238        return self.cgRoot.define()
3239
3240
3241class CGPerSignatureCall(CGThing):
3242    """
3243    This class handles the guts of generating code for a particular
3244    call signature.  A call signature consists of four things:
3245
3246    1) A return type, which can be None to indicate that there is no
3247       actual return value (e.g. this is an attribute setter) or an
3248       IDLType if there's an IDL type involved (including |void|).
3249    2) An argument list, which is allowed to be empty.
3250    3) A name of a native method to call.
3251    4) Whether or not this method is static.
3252
3253    We also need to know whether this is a method or a getter/setter
3254    to do error reporting correctly.
3255
3256    The idlNode parameter can be either a method or an attr. We can query
3257    |idlNode.identifier| in both cases, so we can be agnostic between the two.
3258    """
3259    # XXXbz For now each entry in the argument list is either an
3260    # IDLArgument or a FakeArgument, but longer-term we may want to
3261    # have ways of flagging things like JSContext* or optional_argc in
3262    # there.
3263
3264    def __init__(self, returnType, argsPre, arguments, nativeMethodName, static,
3265                 descriptor, idlNode, argConversionStartsAt=0,
3266                 getter=False, setter=False):
3267        CGThing.__init__(self)
3268        self.returnType = returnType
3269        self.descriptor = descriptor
3270        self.idlNode = idlNode
3271        self.extendedAttributes = descriptor.getExtendedAttributes(idlNode,
3272                                                                   getter=getter,
3273                                                                   setter=setter)
3274        self.argsPre = argsPre
3275        self.arguments = arguments
3276        self.argCount = len(arguments)
3277        cgThings = []
3278        cgThings.extend([CGArgumentConverter(arguments[i], i, self.getArgs(),
3279                                             self.getArgc(), self.descriptor,
3280                                             invalidEnumValueFatal=not setter) for
3281                         i in range(argConversionStartsAt, self.argCount)])
3282
3283        errorResult = None
3284        if self.isFallible():
3285            errorResult = " false"
3286
3287        if idlNode.isMethod() and idlNode.isMaplikeOrSetlikeOrIterableMethod():
3288            if idlNode.maplikeOrSetlikeOrIterable.isMaplike() or \
3289               idlNode.maplikeOrSetlikeOrIterable.isSetlike():
3290                raise TypeError('Maplike/Setlike methods are not supported yet')
3291            else:
3292                cgThings.append(CGIterableMethodGenerator(descriptor,
3293                                                          idlNode.maplikeOrSetlikeOrIterable,
3294                                                          idlNode.identifier.name))
3295        else:
3296            hasCEReactions = idlNode.getExtendedAttribute("CEReactions")
3297            cgThings.append(CGCallGenerator(
3298                errorResult,
3299                self.getArguments(), self.argsPre, returnType,
3300                self.extendedAttributes, descriptor, nativeMethodName,
3301                static, hasCEReactions=hasCEReactions))
3302
3303        self.cgRoot = CGList(cgThings, "\n")
3304
3305    def getArgs(self):
3306        return "args" if self.argCount > 0 else ""
3307
3308    def getArgc(self):
3309        return "argc"
3310
3311    def getArguments(self):
3312        return [(a, process_arg("arg" + str(i), a)) for (i, a) in enumerate(self.arguments)]
3313
3314    def isFallible(self):
3315        return 'infallible' not in self.extendedAttributes
3316
3317    def wrap_return_value(self):
3318        return wrapForType('args.rval()')
3319
3320    def define(self):
3321        return (self.cgRoot.define() + "\n" + self.wrap_return_value())
3322
3323
3324class CGSwitch(CGList):
3325    """
3326    A class to generate code for a switch statement.
3327
3328    Takes three constructor arguments: an expression, a list of cases,
3329    and an optional default.
3330
3331    Each case is a CGCase.  The default is a CGThing for the body of
3332    the default case, if any.
3333    """
3334    def __init__(self, expression, cases, default=None):
3335        CGList.__init__(self, [CGIndenter(c) for c in cases], "\n")
3336        self.prepend(CGWrapper(CGGeneric(expression),
3337                               pre="match ", post=" {"))
3338        if default is not None:
3339            self.append(
3340                CGIndenter(
3341                    CGWrapper(
3342                        CGIndenter(default),
3343                        pre="_ => {\n",
3344                        post="\n}"
3345                    )
3346                )
3347            )
3348
3349        self.append(CGGeneric("}"))
3350
3351
3352class CGCase(CGList):
3353    """
3354    A class to generate code for a case statement.
3355
3356    Takes three constructor arguments: an expression, a CGThing for
3357    the body (allowed to be None if there is no body), and an optional
3358    argument (defaulting to False) for whether to fall through.
3359    """
3360    def __init__(self, expression, body, fallThrough=False):
3361        CGList.__init__(self, [], "\n")
3362        self.append(CGWrapper(CGGeneric(expression), post=" => {"))
3363        bodyList = CGList([body], "\n")
3364        if fallThrough:
3365            raise TypeError("fall through required but unsupported")
3366            # bodyList.append(CGGeneric('panic!("fall through unsupported"); /* Fall through */'))
3367        self.append(CGIndenter(bodyList))
3368        self.append(CGGeneric("}"))
3369
3370
3371class CGGetterCall(CGPerSignatureCall):
3372    """
3373    A class to generate a native object getter call for a particular IDL
3374    getter.
3375    """
3376    def __init__(self, argsPre, returnType, nativeMethodName, descriptor, attr):
3377        CGPerSignatureCall.__init__(self, returnType, argsPre, [],
3378                                    nativeMethodName, attr.isStatic(), descriptor,
3379                                    attr, getter=True)
3380
3381
3382class FakeArgument():
3383    """
3384    A class that quacks like an IDLArgument.  This is used to make
3385    setters look like method calls or for special operations.
3386    """
3387    def __init__(self, type, interfaceMember, allowTreatNonObjectAsNull=False):
3388        self.type = type
3389        self.optional = False
3390        self.variadic = False
3391        self.defaultValue = None
3392        self._allowTreatNonObjectAsNull = allowTreatNonObjectAsNull
3393        self.treatNullAs = interfaceMember.treatNullAs
3394        self.enforceRange = False
3395        self.clamp = False
3396
3397    def allowTreatNonCallableAsNull(self):
3398        return self._allowTreatNonObjectAsNull
3399
3400
3401class CGSetterCall(CGPerSignatureCall):
3402    """
3403    A class to generate a native object setter call for a particular IDL
3404    setter.
3405    """
3406    def __init__(self, argsPre, argType, nativeMethodName, descriptor, attr):
3407        CGPerSignatureCall.__init__(self, None, argsPre,
3408                                    [FakeArgument(argType, attr, allowTreatNonObjectAsNull=True)],
3409                                    nativeMethodName, attr.isStatic(), descriptor, attr,
3410                                    setter=True)
3411
3412    def wrap_return_value(self):
3413        # We have no return value
3414        return "\nreturn true;"
3415
3416    def getArgc(self):
3417        return "1"
3418
3419
3420class CGAbstractStaticBindingMethod(CGAbstractMethod):
3421    """
3422    Common class to generate the JSNatives for all our static methods, getters
3423    and setters.  This will generate the function declaration and unwrap the
3424    global object.  Subclasses are expected to override the generate_code
3425    function to do the rest of the work.  This function should return a
3426    CGThing which is already properly indented.
3427    """
3428    def __init__(self, descriptor, name):
3429        args = [
3430            Argument('*mut JSContext', 'cx'),
3431            Argument('libc::c_uint', 'argc'),
3432            Argument('*mut JSVal', 'vp'),
3433        ]
3434        CGAbstractMethod.__init__(self, descriptor, name, "bool", args, extern=True)
3435        self.exposureSet = descriptor.interface.exposureSet
3436
3437    def definition_body(self):
3438        preamble = "let global = GlobalScope::from_object(JS_CALLEE(cx, vp).to_object());\n"
3439        if len(self.exposureSet) == 1:
3440            preamble += """
3441let global = DomRoot::downcast::<dom::types::%s>(global).unwrap();
3442""" % list(self.exposureSet)[0]
3443        return CGList([CGGeneric(preamble), self.generate_code()])
3444
3445    def generate_code(self):
3446        raise NotImplementedError  # Override me!
3447
3448
3449class CGSpecializedMethod(CGAbstractExternMethod):
3450    """
3451    A class for generating the C++ code for a specialized method that the JIT
3452    can call with lower overhead.
3453    """
3454    def __init__(self, descriptor, method):
3455        self.method = method
3456        name = method.identifier.name
3457        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', '_obj'),
3458                Argument('*const %s' % descriptor.concreteType, 'this'),
3459                Argument('*const JSJitMethodCallArgs', 'args')]
3460        CGAbstractExternMethod.__init__(self, descriptor, name, 'bool', args)
3461
3462    def definition_body(self):
3463        nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
3464                                                        self.method)
3465        return CGWrapper(CGMethodCall([], nativeName, self.method.isStatic(),
3466                                      self.descriptor, self.method),
3467                         pre="let this = &*this;\n"
3468                             "let args = &*args;\n"
3469                             "let argc = args._base.argc_;\n")
3470
3471    @staticmethod
3472    def makeNativeName(descriptor, method):
3473        name = method.identifier.name
3474        nativeName = descriptor.binaryNameFor(name)
3475        if nativeName == name:
3476            nativeName = descriptor.internalNameFor(name)
3477        return MakeNativeName(nativeName)
3478
3479
3480class CGStaticMethod(CGAbstractStaticBindingMethod):
3481    """
3482    A class for generating the Rust code for an IDL static method.
3483    """
3484    def __init__(self, descriptor, method):
3485        self.method = method
3486        name = method.identifier.name
3487        CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
3488
3489    def generate_code(self):
3490        nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
3491                                                        self.method)
3492        setupArgs = CGGeneric("let args = CallArgs::from_vp(vp, argc);\n")
3493        call = CGMethodCall(["&global"], nativeName, True, self.descriptor, self.method)
3494        return CGList([setupArgs, call])
3495
3496
3497class CGSpecializedGetter(CGAbstractExternMethod):
3498    """
3499    A class for generating the code for a specialized attribute getter
3500    that the JIT can call with lower overhead.
3501    """
3502    def __init__(self, descriptor, attr):
3503        self.attr = attr
3504        name = 'get_' + descriptor.internalNameFor(attr.identifier.name)
3505        args = [Argument('*mut JSContext', 'cx'),
3506                Argument('HandleObject', '_obj'),
3507                Argument('*const %s' % descriptor.concreteType, 'this'),
3508                Argument('JSJitGetterCallArgs', 'args')]
3509        CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
3510
3511    def definition_body(self):
3512        nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
3513                                                        self.attr)
3514
3515        return CGWrapper(CGGetterCall([], self.attr.type, nativeName,
3516                                      self.descriptor, self.attr),
3517                         pre="let this = &*this;\n")
3518
3519    @staticmethod
3520    def makeNativeName(descriptor, attr):
3521        name = attr.identifier.name
3522        nativeName = descriptor.binaryNameFor(name)
3523        if nativeName == name:
3524            nativeName = descriptor.internalNameFor(name)
3525        nativeName = MakeNativeName(nativeName)
3526        infallible = ('infallible' in
3527                      descriptor.getExtendedAttributes(attr, getter=True))
3528        if attr.type.nullable() or not infallible:
3529            return "Get" + nativeName
3530
3531        return nativeName
3532
3533
3534class CGStaticGetter(CGAbstractStaticBindingMethod):
3535    """
3536    A class for generating the C++ code for an IDL static attribute getter.
3537    """
3538    def __init__(self, descriptor, attr):
3539        self.attr = attr
3540        name = 'get_' + attr.identifier.name
3541        CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
3542
3543    def generate_code(self):
3544        nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
3545                                                        self.attr)
3546        setupArgs = CGGeneric("let args = CallArgs::from_vp(vp, argc);\n")
3547        call = CGGetterCall(["&global"], self.attr.type, nativeName, self.descriptor,
3548                            self.attr)
3549        return CGList([setupArgs, call])
3550
3551
3552class CGSpecializedSetter(CGAbstractExternMethod):
3553    """
3554    A class for generating the code for a specialized attribute setter
3555    that the JIT can call with lower overhead.
3556    """
3557    def __init__(self, descriptor, attr):
3558        self.attr = attr
3559        name = 'set_' + descriptor.internalNameFor(attr.identifier.name)
3560        args = [Argument('*mut JSContext', 'cx'),
3561                Argument('HandleObject', 'obj'),
3562                Argument('*const %s' % descriptor.concreteType, 'this'),
3563                Argument('JSJitSetterCallArgs', 'args')]
3564        CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
3565
3566    def definition_body(self):
3567        nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
3568                                                        self.attr)
3569        return CGWrapper(CGSetterCall([], self.attr.type, nativeName,
3570                                      self.descriptor, self.attr),
3571                         pre="let this = &*this;\n")
3572
3573    @staticmethod
3574    def makeNativeName(descriptor, attr):
3575        name = attr.identifier.name
3576        nativeName = descriptor.binaryNameFor(name)
3577        if nativeName == name:
3578            nativeName = descriptor.internalNameFor(name)
3579        return "Set" + MakeNativeName(nativeName)
3580
3581
3582class CGStaticSetter(CGAbstractStaticBindingMethod):
3583    """
3584    A class for generating the C++ code for an IDL static attribute setter.
3585    """
3586    def __init__(self, descriptor, attr):
3587        self.attr = attr
3588        name = 'set_' + attr.identifier.name
3589        CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
3590
3591    def generate_code(self):
3592        nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
3593                                                        self.attr)
3594        checkForArg = CGGeneric(
3595            "let args = CallArgs::from_vp(vp, argc);\n"
3596            "if argc == 0 {\n"
3597            "    throw_type_error(cx, \"Not enough arguments to %s setter.\");\n"
3598            "    return false;\n"
3599            "}" % self.attr.identifier.name)
3600        call = CGSetterCall(["&global"], self.attr.type, nativeName, self.descriptor,
3601                            self.attr)
3602        return CGList([checkForArg, call])
3603
3604
3605class CGSpecializedForwardingSetter(CGSpecializedSetter):
3606    """
3607    A class for generating the code for an IDL attribute forwarding setter.
3608    """
3609    def __init__(self, descriptor, attr):
3610        CGSpecializedSetter.__init__(self, descriptor, attr)
3611
3612    def definition_body(self):
3613        attrName = self.attr.identifier.name
3614        forwardToAttrName = self.attr.getExtendedAttribute("PutForwards")[0]
3615        # JS_GetProperty and JS_SetProperty can only deal with ASCII
3616        assert all(ord(c) < 128 for c in attrName)
3617        assert all(ord(c) < 128 for c in forwardToAttrName)
3618        return CGGeneric("""\
3619rooted!(in(cx) let mut v = UndefinedValue());
3620if !JS_GetProperty(cx, obj, %s as *const u8 as *const libc::c_char, v.handle_mut()) {
3621    return false;
3622}
3623if !v.is_object() {
3624    throw_type_error(cx, "Value.%s is not an object.");
3625    return false;
3626}
3627rooted!(in(cx) let target_obj = v.to_object());
3628JS_SetProperty(cx, target_obj.handle(), %s as *const u8 as *const libc::c_char, args.get(0))
3629""" % (str_to_const_array(attrName), attrName, str_to_const_array(forwardToAttrName)))
3630
3631
3632class CGSpecializedReplaceableSetter(CGSpecializedSetter):
3633    """
3634    A class for generating the code for an IDL replaceable attribute setter.
3635    """
3636    def __init__(self, descriptor, attr):
3637        CGSpecializedSetter.__init__(self, descriptor, attr)
3638
3639    def definition_body(self):
3640        assert self.attr.readonly
3641        name = str_to_const_array(self.attr.identifier.name)
3642        # JS_DefineProperty can only deal with ASCII.
3643        assert all(ord(c) < 128 for c in name)
3644        return CGGeneric("""\
3645JS_DefineProperty(cx, obj, %s as *const u8 as *const libc::c_char,
3646                  args.get(0), JSPROP_ENUMERATE, None, None)""" % name)
3647
3648
3649class CGMemberJITInfo(CGThing):
3650    """
3651    A class for generating the JITInfo for a property that points to
3652    our specialized getter and setter.
3653    """
3654    def __init__(self, descriptor, member):
3655        self.member = member
3656        self.descriptor = descriptor
3657
3658    def defineJitInfo(self, infoName, opName, opType, infallible, movable,
3659                      aliasSet, alwaysInSlot, lazilyInSlot, slotIndex,
3660                      returnTypes, args):
3661        """
3662        aliasSet is a JSJitInfo_AliasSet value, without the "JSJitInfo_AliasSet::" bit.
3663
3664        args is None if we don't want to output argTypes for some
3665        reason (e.g. we have overloads or we're not a method) and
3666        otherwise an iterable of the arguments for this method.
3667        """
3668        assert not movable or aliasSet != "AliasEverything"  # Can't move write-aliasing things
3669        assert not alwaysInSlot or movable  # Things always in slots had better be movable
3670
3671        def jitInfoInitializer(isTypedMethod):
3672            initializer = fill(
3673                """
3674                JSJitInfo {
3675                    call: ${opName} as *const os::raw::c_void,
3676                    protoID: PrototypeList::ID::${name} as u16,
3677                    depth: ${depth},
3678                    _bitfield_1: new_jsjitinfo_bitfield_1!(
3679                        JSJitInfo_OpType::${opType} as u8,
3680                        JSJitInfo_AliasSet::${aliasSet} as u8,
3681                        JSValueType::${returnType} as u8,
3682                        ${isInfallible},
3683                        ${isMovable},
3684                        ${isEliminatable},
3685                        ${isAlwaysInSlot},
3686                        ${isLazilyCachedInSlot},
3687                        ${isTypedMethod},
3688                        ${slotIndex},
3689                    ),
3690                }
3691                """,
3692                opName=opName,
3693                name=self.descriptor.name,
3694                depth=self.descriptor.interface.inheritanceDepth(),
3695                opType=opType,
3696                aliasSet=aliasSet,
3697                returnType=reduce(CGMemberJITInfo.getSingleReturnType, returnTypes,
3698                                  ""),
3699                isInfallible=toStringBool(infallible),
3700                isMovable=toStringBool(movable),
3701                # FIXME(nox): https://github.com/servo/servo/issues/10991
3702                isEliminatable=toStringBool(False),
3703                isAlwaysInSlot=toStringBool(alwaysInSlot),
3704                isLazilyCachedInSlot=toStringBool(lazilyInSlot),
3705                isTypedMethod=toStringBool(isTypedMethod),
3706                slotIndex=slotIndex)
3707            return initializer.rstrip()
3708
3709        if args is not None:
3710            argTypes = "%s_argTypes" % infoName
3711            args = [CGMemberJITInfo.getJSArgType(arg.type) for arg in args]
3712            args.append("JSJitInfo_ArgType::ArgTypeListEnd as i32")
3713            argTypesDecl = (
3714                "const %s: [i32; %d] = [ %s ];\n" %
3715                (argTypes, len(args), ", ".join(args)))
3716            return fill(
3717                """
3718                $*{argTypesDecl}
3719                const ${infoName}: JSTypedMethodJitInfo = JSTypedMethodJitInfo {
3720                    base: ${jitInfo},
3721                    argTypes: &${argTypes} as *const _ as *const JSJitInfo_ArgType,
3722                };
3723                """,
3724                argTypesDecl=argTypesDecl,
3725                infoName=infoName,
3726                jitInfo=indent(jitInfoInitializer(True)),
3727                argTypes=argTypes)
3728
3729        return ("\n"
3730                "const %s: JSJitInfo = %s;\n"
3731                % (infoName, jitInfoInitializer(False)))
3732
3733    def define(self):
3734        if self.member.isAttr():
3735            internalMemberName = self.descriptor.internalNameFor(self.member.identifier.name)
3736            getterinfo = ("%s_getterinfo" % internalMemberName)
3737            getter = ("get_%s" % internalMemberName)
3738            getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True)
3739
3740            movable = self.mayBeMovable() and getterinfal
3741            aliasSet = self.aliasSet()
3742
3743            isAlwaysInSlot = self.member.getExtendedAttribute("StoreInSlot")
3744            if self.member.slotIndices is not None:
3745                assert isAlwaysInSlot or self.member.getExtendedAttribute("Cached")
3746                isLazilyCachedInSlot = not isAlwaysInSlot
3747                slotIndex = memberReservedSlot(self.member)  # noqa:FIXME: memberReservedSlot is not defined
3748                # We'll statically assert that this is not too big in
3749                # CGUpdateMemberSlotsMethod, in the case when
3750                # isAlwaysInSlot is true.
3751            else:
3752                isLazilyCachedInSlot = False
3753                slotIndex = "0"
3754
3755            result = self.defineJitInfo(getterinfo, getter, "Getter",
3756                                        getterinfal, movable, aliasSet,
3757                                        isAlwaysInSlot, isLazilyCachedInSlot,
3758                                        slotIndex,
3759                                        [self.member.type], None)
3760            if (not self.member.readonly or self.member.getExtendedAttribute("PutForwards")
3761                    or self.member.getExtendedAttribute("Replaceable")):
3762                setterinfo = ("%s_setterinfo" % internalMemberName)
3763                setter = ("set_%s" % internalMemberName)
3764                # Setters are always fallible, since they have to do a typed unwrap.
3765                result += self.defineJitInfo(setterinfo, setter, "Setter",
3766                                             False, False, "AliasEverything",
3767                                             False, False, "0",
3768                                             [BuiltinTypes[IDLBuiltinType.Types.void]],
3769                                             None)
3770            return result
3771        if self.member.isMethod():
3772            methodinfo = ("%s_methodinfo" % self.member.identifier.name)
3773            method = ("%s" % self.member.identifier.name)
3774
3775            # Methods are infallible if they are infallible, have no arguments
3776            # to unwrap, and have a return type that's infallible to wrap up for
3777            # return.
3778            sigs = self.member.signatures()
3779            if len(sigs) != 1:
3780                # Don't handle overloading. If there's more than one signature,
3781                # one of them must take arguments.
3782                methodInfal = False
3783                args = None
3784                movable = False
3785            else:
3786                sig = sigs[0]
3787                # For methods that affect nothing, it's OK to set movable to our
3788                # notion of infallible on the C++ side, without considering
3789                # argument conversions, since argument conversions that can
3790                # reliably throw would be effectful anyway and the jit doesn't
3791                # move effectful things.
3792                hasInfallibleImpl = "infallible" in self.descriptor.getExtendedAttributes(self.member)
3793                movable = self.mayBeMovable() and hasInfallibleImpl
3794                # XXXbz can we move the smarts about fallibility due to arg
3795                # conversions into the JIT, using our new args stuff?
3796                if (len(sig[1]) != 0):
3797                    # We have arguments or our return-value boxing can fail
3798                    methodInfal = False
3799                else:
3800                    methodInfal = hasInfallibleImpl
3801                # For now, only bother to output args if we're side-effect-free.
3802                if self.member.affects == "Nothing":
3803                    args = sig[1]
3804                else:
3805                    args = None
3806
3807            aliasSet = self.aliasSet()
3808            result = self.defineJitInfo(methodinfo, method, "Method",
3809                                        methodInfal, movable, aliasSet,
3810                                        False, False, "0",
3811                                        [s[0] for s in sigs], args)
3812            return result
3813        raise TypeError("Illegal member type to CGPropertyJITInfo")
3814
3815    def mayBeMovable(self):
3816        """
3817        Returns whether this attribute or method may be movable, just
3818        based on Affects/DependsOn annotations.
3819        """
3820        affects = self.member.affects
3821        dependsOn = self.member.dependsOn
3822        assert affects in IDLInterfaceMember.AffectsValues
3823        assert dependsOn in IDLInterfaceMember.DependsOnValues
3824        # Things that are DependsOn=DeviceState are not movable, because we
3825        # don't want them coalesced with each other or loop-hoisted, since
3826        # their return value can change even if nothing is going on from our
3827        # point of view.
3828        return (affects == "Nothing" and
3829                (dependsOn != "Everything" and dependsOn != "DeviceState"))
3830
3831    def aliasSet(self):
3832        """Returns the alias set to store in the jitinfo.  This may not be the
3833        effective alias set the JIT uses, depending on whether we have enough
3834        information about our args to allow the JIT to prove that effectful
3835        argument conversions won't happen.
3836
3837        """
3838        dependsOn = self.member.dependsOn
3839        assert dependsOn in IDLInterfaceMember.DependsOnValues
3840
3841        if dependsOn == "Nothing" or dependsOn == "DeviceState":
3842            assert self.member.affects == "Nothing"
3843            return "AliasNone"
3844
3845        if dependsOn == "DOMState":
3846            assert self.member.affects == "Nothing"
3847            return "AliasDOMSets"
3848
3849        return "AliasEverything"
3850
3851    @staticmethod
3852    def getJSReturnTypeTag(t):
3853        if t.nullable():
3854            # Sometimes it might return null, sometimes not
3855            return "JSVAL_TYPE_UNKNOWN"
3856        if t.isVoid():
3857            # No return, every time
3858            return "JSVAL_TYPE_UNDEFINED"
3859        if t.isSequence():
3860            return "JSVAL_TYPE_OBJECT"
3861        if t.isRecord():
3862            return "JSVAL_TYPE_OBJECT"
3863        if t.isPromise():
3864            return "JSVAL_TYPE_OBJECT"
3865        if t.isGeckoInterface():
3866            return "JSVAL_TYPE_OBJECT"
3867        if t.isString():
3868            return "JSVAL_TYPE_STRING"
3869        if t.isEnum():
3870            return "JSVAL_TYPE_STRING"
3871        if t.isCallback():
3872            return "JSVAL_TYPE_OBJECT"
3873        if t.isAny():
3874            # The whole point is to return various stuff
3875            return "JSVAL_TYPE_UNKNOWN"
3876        if t.isObject():
3877            return "JSVAL_TYPE_OBJECT"
3878        if t.isSpiderMonkeyInterface():
3879            return "JSVAL_TYPE_OBJECT"
3880        if t.isUnion():
3881            u = t.unroll()
3882            if u.hasNullableType:
3883                # Might be null or not
3884                return "JSVAL_TYPE_UNKNOWN"
3885            return reduce(CGMemberJITInfo.getSingleReturnType,
3886                          u.flatMemberTypes, "")
3887        if t.isDictionary():
3888            return "JSVAL_TYPE_OBJECT"
3889        if t.isDate():
3890            return "JSVAL_TYPE_OBJECT"
3891        if not t.isPrimitive():
3892            raise TypeError("No idea what type " + str(t) + " is.")
3893        tag = t.tag()
3894        if tag == IDLType.Tags.bool:
3895            return "JSVAL_TYPE_BOOLEAN"
3896        if tag in [IDLType.Tags.int8, IDLType.Tags.uint8,
3897                   IDLType.Tags.int16, IDLType.Tags.uint16,
3898                   IDLType.Tags.int32]:
3899            return "JSVAL_TYPE_INT32"
3900        if tag in [IDLType.Tags.int64, IDLType.Tags.uint64,
3901                   IDLType.Tags.unrestricted_float, IDLType.Tags.float,
3902                   IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
3903            # These all use JS_NumberValue, which can return int or double.
3904            # But TI treats "double" as meaning "int or double", so we're
3905            # good to return JSVAL_TYPE_DOUBLE here.
3906            return "JSVAL_TYPE_DOUBLE"
3907        if tag != IDLType.Tags.uint32:
3908            raise TypeError("No idea what type " + str(t) + " is.")
3909        # uint32 is sometimes int and sometimes double.
3910        return "JSVAL_TYPE_DOUBLE"
3911
3912    @staticmethod
3913    def getSingleReturnType(existingType, t):
3914        type = CGMemberJITInfo.getJSReturnTypeTag(t)
3915        if existingType == "":
3916            # First element of the list; just return its type
3917            return type
3918
3919        if type == existingType:
3920            return existingType
3921        if ((type == "JSVAL_TYPE_DOUBLE" and
3922             existingType == "JSVAL_TYPE_INT32") or
3923            (existingType == "JSVAL_TYPE_DOUBLE" and
3924             type == "JSVAL_TYPE_INT32")):
3925            # Promote INT32 to DOUBLE as needed
3926            return "JSVAL_TYPE_DOUBLE"
3927        # Different types
3928        return "JSVAL_TYPE_UNKNOWN"
3929
3930    @staticmethod
3931    def getJSArgType(t):
3932        assert not t.isVoid()
3933        if t.nullable():
3934            # Sometimes it might return null, sometimes not
3935            return "JSJitInfo_ArgType::Null as i32 | %s" % CGMemberJITInfo.getJSArgType(t.inner)
3936        if t.isSequence():
3937            return "JSJitInfo_ArgType::Object as i32"
3938        if t.isGeckoInterface():
3939            return "JSJitInfo_ArgType::Object as i32"
3940        if t.isString():
3941            return "JSJitInfo_ArgType::String as i32"
3942        if t.isEnum():
3943            return "JSJitInfo_ArgType::String as i32"
3944        if t.isCallback():
3945            return "JSJitInfo_ArgType::Object as i32"
3946        if t.isAny():
3947            # The whole point is to return various stuff
3948            return "JSJitInfo_ArgType::Any as i32"
3949        if t.isObject():
3950            return "JSJitInfo_ArgType::Object as i32"
3951        if t.isSpiderMonkeyInterface():
3952            return "JSJitInfo_ArgType::Object as i32"
3953        if t.isUnion():
3954            u = t.unroll()
3955            type = "JSJitInfo::Null as i32" if u.hasNullableType else ""
3956            return reduce(CGMemberJITInfo.getSingleArgType,
3957                          u.flatMemberTypes, type)
3958        if t.isDictionary():
3959            return "JSJitInfo_ArgType::Object as i32"
3960        if t.isDate():
3961            return "JSJitInfo_ArgType::Object as i32"
3962        if not t.isPrimitive():
3963            raise TypeError("No idea what type " + str(t) + " is.")
3964        tag = t.tag()
3965        if tag == IDLType.Tags.bool:
3966            return "JSJitInfo_ArgType::Boolean as i32"
3967        if tag in [IDLType.Tags.int8, IDLType.Tags.uint8,
3968                   IDLType.Tags.int16, IDLType.Tags.uint16,
3969                   IDLType.Tags.int32]:
3970            return "JSJitInfo_ArgType::Integer as i32"
3971        if tag in [IDLType.Tags.int64, IDLType.Tags.uint64,
3972                   IDLType.Tags.unrestricted_float, IDLType.Tags.float,
3973                   IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
3974            # These all use JS_NumberValue, which can return int or double.
3975            # But TI treats "double" as meaning "int or double", so we're
3976            # good to return JSVAL_TYPE_DOUBLE here.
3977            return "JSJitInfo_ArgType::Double as i32"
3978        if tag != IDLType.Tags.uint32:
3979            raise TypeError("No idea what type " + str(t) + " is.")
3980        # uint32 is sometimes int and sometimes double.
3981        return "JSJitInfo_ArgType::Double as i32"
3982
3983    @staticmethod
3984    def getSingleArgType(existingType, t):
3985        type = CGMemberJITInfo.getJSArgType(t)
3986        if existingType == "":
3987            # First element of the list; just return its type
3988            return type
3989
3990        if type == existingType:
3991            return existingType
3992        return "%s | %s" % (existingType, type)
3993
3994
3995def getEnumValueName(value):
3996    # Some enum values can be empty strings.  Others might have weird
3997    # characters in them.  Deal with the former by returning "_empty",
3998    # deal with possible name collisions from that by throwing if the
3999    # enum value is actually "_empty", and throw on any value
4000    # containing non-ASCII chars for now. Replace all chars other than
4001    # [0-9A-Za-z_] with '_'.
4002    if re.match("[^\x20-\x7E]", value):
4003        raise SyntaxError('Enum value "' + value + '" contains non-ASCII characters')
4004    if re.match("^[0-9]", value):
4005        raise SyntaxError('Enum value "' + value + '" starts with a digit')
4006    value = re.sub(r'[^0-9A-Za-z_]', '_', value)
4007    if re.match("^_[A-Z]|__", value):
4008        raise SyntaxError('Enum value "' + value + '" is reserved by the C++ spec')
4009    if value == "_empty":
4010        raise SyntaxError('"_empty" is not an IDL enum value we support yet')
4011    if value == "":
4012        return "_empty"
4013    return MakeNativeName(value)
4014
4015
4016class CGEnum(CGThing):
4017    def __init__(self, enum):
4018        CGThing.__init__(self)
4019
4020        ident = enum.identifier.name
4021        decl = """\
4022#[repr(usize)]
4023#[derive(Copy, Clone, Debug, JSTraceable, MallocSizeOf, PartialEq)]
4024pub enum %s {
4025    %s
4026}
4027""" % (ident, ",\n    ".join(map(getEnumValueName, enum.values())))
4028
4029        pairs = ",\n    ".join(['("%s", super::%s::%s)' % (val, ident, getEnumValueName(val)) for val in enum.values()])
4030
4031        inner = string.Template("""\
4032use dom::bindings::conversions::ToJSValConvertible;
4033use js::jsapi::{JSContext, MutableHandleValue};
4034use js::jsval::JSVal;
4035
4036pub const pairs: &'static [(&'static str, super::${ident})] = &[
4037    ${pairs},
4038];
4039
4040impl super::${ident} {
4041    pub fn as_str(&self) -> &'static str {
4042        pairs[*self as usize].0
4043    }
4044}
4045
4046impl Default for super::${ident} {
4047    fn default() -> super::${ident} {
4048        pairs[0].1
4049    }
4050}
4051
4052impl ToJSValConvertible for super::${ident} {
4053    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
4054        pairs[*self as usize].0.to_jsval(cx, rval);
4055    }
4056}
4057    """).substitute({
4058            'ident': ident,
4059            'pairs': pairs
4060        })
4061        self.cgRoot = CGList([
4062            CGGeneric(decl),
4063            CGNamespace.build([ident + "Values"],
4064                              CGIndenter(CGGeneric(inner)), public=True),
4065        ])
4066
4067    def define(self):
4068        return self.cgRoot.define()
4069
4070
4071def convertConstIDLValueToRust(value):
4072    tag = value.type.tag()
4073    if tag in [IDLType.Tags.int8, IDLType.Tags.uint8,
4074               IDLType.Tags.int16, IDLType.Tags.uint16,
4075               IDLType.Tags.int32, IDLType.Tags.uint32,
4076               IDLType.Tags.int64, IDLType.Tags.uint64,
4077               IDLType.Tags.unrestricted_float, IDLType.Tags.float,
4078               IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
4079        return str(value.value)
4080
4081    if tag == IDLType.Tags.bool:
4082        return toStringBool(value.value)
4083
4084    raise TypeError("Const value of unhandled type: " + value.type)
4085
4086
4087class CGConstant(CGThing):
4088    def __init__(self, constant):
4089        CGThing.__init__(self)
4090        self.constant = constant
4091
4092    def define(self):
4093        name = self.constant.identifier.name
4094        value = convertConstIDLValueToRust(self.constant.value)
4095
4096        tag = self.constant.value.type.tag()
4097        const_type = builtinNames[self.constant.value.type.tag()]
4098        # Finite<f32> or Finite<f64> cannot be used un a constant declaration.
4099        # Remote the Finite type from restricted float and double tag declarations.
4100        if tag == IDLType.Tags.float:
4101            const_type = "f32"
4102        elif tag == IDLType.Tags.double:
4103            const_type = "f64"
4104
4105        return "pub const %s: %s = %s;\n" % (name, const_type, value)
4106
4107
4108def getUnionTypeTemplateVars(type, descriptorProvider):
4109    if type.isGeckoInterface():
4110        name = type.inner.identifier.name
4111        typeName = descriptorProvider.getDescriptor(name).returnType
4112    elif type.isEnum():
4113        name = type.inner.identifier.name
4114        typeName = name
4115    elif type.isDictionary():
4116        name = type.name
4117        typeName = name
4118    elif type.isSequence() or type.isRecord():
4119        name = type.name
4120        inner = getUnionTypeTemplateVars(innerContainerType(type), descriptorProvider)
4121        typeName = wrapInNativeContainerType(type, CGGeneric(inner["typeName"])).define()
4122    elif type.isByteString():
4123        name = type.name
4124        typeName = "ByteString"
4125    elif type.isDOMString():
4126        name = type.name
4127        typeName = "DOMString"
4128    elif type.isUSVString():
4129        name = type.name
4130        typeName = "USVString"
4131    elif type.isPrimitive():
4132        name = type.name
4133        typeName = builtinNames[type.tag()]
4134    elif type.isObject():
4135        name = type.name
4136        typeName = "Heap<*mut JSObject>"
4137    else:
4138        raise TypeError("Can't handle %s in unions yet" % type)
4139
4140    info = getJSToNativeConversionInfo(
4141        type, descriptorProvider, failureCode="return Ok(None);",
4142        exceptionCode='return Err(());',
4143        isDefinitelyObject=True,
4144        isMember="Union")
4145    template = info.template
4146
4147    jsConversion = string.Template(template).substitute({
4148        "val": "value",
4149    })
4150    jsConversion = CGWrapper(CGGeneric(jsConversion), pre="Ok(Some(", post="))")
4151
4152    return {
4153        "name": name,
4154        "typeName": typeName,
4155        "jsConversion": jsConversion,
4156    }
4157
4158
4159class CGUnionStruct(CGThing):
4160    def __init__(self, type, descriptorProvider):
4161        assert not type.nullable()
4162        assert not type.hasNullableType
4163
4164        CGThing.__init__(self)
4165        self.type = type
4166        self.descriptorProvider = descriptorProvider
4167
4168    def membersNeedTracing(self):
4169        for t in self.type.flatMemberTypes:
4170            if type_needs_tracing(t):
4171                return True
4172        return False
4173
4174    def define(self):
4175        templateVars = map(lambda t: (getUnionTypeTemplateVars(t, self.descriptorProvider),
4176                                      type_needs_tracing(t)),
4177                           self.type.flatMemberTypes)
4178        enumValues = [
4179            "    %s(%s)," % (v["name"], "RootedTraceableBox<%s>" % v["typeName"] if trace else v["typeName"])
4180            for (v, trace) in templateVars
4181        ]
4182        enumConversions = [
4183            "            %s::%s(ref inner) => inner.to_jsval(cx, rval),"
4184            % (self.type, v["name"]) for (v, _) in templateVars
4185        ]
4186        return ("""\
4187#[derive(JSTraceable)]
4188pub enum %s {
4189%s
4190}
4191
4192impl ToJSValConvertible for %s {
4193    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
4194        match *self {
4195%s
4196        }
4197    }
4198}
4199""") % (self.type, "\n".join(enumValues), self.type, "\n".join(enumConversions))
4200
4201
4202class CGUnionConversionStruct(CGThing):
4203    def __init__(self, type, descriptorProvider):
4204        assert not type.nullable()
4205        assert not type.hasNullableType
4206
4207        CGThing.__init__(self)
4208        self.type = type
4209        self.descriptorProvider = descriptorProvider
4210
4211    def membersNeedTracing(self):
4212        for t in self.type.flatMemberTypes:
4213            if type_needs_tracing(t):
4214                return True
4215        return False
4216
4217    def from_jsval(self):
4218        memberTypes = self.type.flatMemberTypes
4219        names = []
4220        conversions = []
4221
4222        def get_name(memberType):
4223            if self.type.isGeckoInterface():
4224                return memberType.inner.identifier.name
4225
4226            return memberType.name
4227
4228        def get_match(name):
4229            return (
4230                "match %s::TryConvertTo%s(cx, value) {\n"
4231                "    Err(_) => return Err(()),\n"
4232                "    Ok(Some(value)) => return Ok(ConversionResult::Success(%s::%s(value))),\n"
4233                "    Ok(None) => (),\n"
4234                "}\n") % (self.type, name, self.type, name)
4235
4236        interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes)
4237        if len(interfaceMemberTypes) > 0:
4238            typeNames = [get_name(memberType) for memberType in interfaceMemberTypes]
4239            interfaceObject = CGList(CGGeneric(get_match(typeName)) for typeName in typeNames)
4240            names.extend(typeNames)
4241        else:
4242            interfaceObject = None
4243
4244        arrayObjectMemberTypes = filter(lambda t: t.isSequence(), memberTypes)
4245        if len(arrayObjectMemberTypes) > 0:
4246            assert len(arrayObjectMemberTypes) == 1
4247            typeName = arrayObjectMemberTypes[0].name
4248            arrayObject = CGGeneric(get_match(typeName))
4249            names.append(typeName)
4250        else:
4251            arrayObject = None
4252
4253        dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes)
4254        if len(dateObjectMemberTypes) > 0:
4255            assert len(dateObjectMemberTypes) == 1
4256            raise TypeError("Can't handle dates in unions.")
4257        else:
4258            dateObject = None
4259
4260        callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes)
4261        if len(callbackMemberTypes) > 0:
4262            assert len(callbackMemberTypes) == 1
4263            raise TypeError("Can't handle callbacks in unions.")
4264        else:
4265            callbackObject = None
4266
4267        dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes)
4268        if len(dictionaryMemberTypes) > 0:
4269            assert len(dictionaryMemberTypes) == 1
4270            typeName = dictionaryMemberTypes[0].name
4271            dictionaryObject = CGGeneric(get_match(typeName))
4272            names.append(typeName)
4273        else:
4274            dictionaryObject = None
4275
4276        objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
4277        if len(objectMemberTypes) > 0:
4278            assert len(objectMemberTypes) == 1
4279            typeName = objectMemberTypes[0].name
4280            object = CGGeneric(get_match(typeName))
4281            names.append(typeName)
4282        else:
4283            object = None
4284
4285        mozMapMemberTypes = filter(lambda t: t.isRecord(), memberTypes)
4286        if len(mozMapMemberTypes) > 0:
4287            assert len(mozMapMemberTypes) == 1
4288            typeName = mozMapMemberTypes[0].name
4289            mozMapObject = CGGeneric(get_match(typeName))
4290            names.append(typeName)
4291        else:
4292            mozMapObject = None
4293
4294        hasObjectTypes = interfaceObject or arrayObject or dateObject or object or mozMapObject
4295        if hasObjectTypes:
4296            # "object" is not distinguishable from other types
4297            assert not object or not (interfaceObject or arrayObject or dateObject or callbackObject or mozMapObject)
4298            templateBody = CGList([], "\n")
4299            if interfaceObject:
4300                templateBody.append(interfaceObject)
4301            if arrayObject:
4302                templateBody.append(arrayObject)
4303            if mozMapObject:
4304                templateBody.append(mozMapObject)
4305            conversions.append(CGIfWrapper("value.get().is_object()", templateBody))
4306
4307        if dictionaryObject:
4308            assert not hasObjectTypes
4309            conversions.append(dictionaryObject)
4310
4311        stringTypes = [t for t in memberTypes if t.isString() or t.isEnum()]
4312        numericTypes = [t for t in memberTypes if t.isNumeric()]
4313        booleanTypes = [t for t in memberTypes if t.isBoolean()]
4314        if stringTypes or numericTypes or booleanTypes:
4315            assert len(stringTypes) <= 1
4316            assert len(numericTypes) <= 1
4317            assert len(booleanTypes) <= 1
4318
4319            def getStringOrPrimitiveConversion(memberType):
4320                typename = get_name(memberType)
4321                return CGGeneric(get_match(typename))
4322            other = []
4323            stringConversion = map(getStringOrPrimitiveConversion, stringTypes)
4324            numericConversion = map(getStringOrPrimitiveConversion, numericTypes)
4325            booleanConversion = map(getStringOrPrimitiveConversion, booleanTypes)
4326            if stringConversion:
4327                if booleanConversion:
4328                    other.append(CGIfWrapper("value.get().is_boolean()", booleanConversion[0]))
4329                if numericConversion:
4330                    other.append(CGIfWrapper("value.get().is_number()", numericConversion[0]))
4331                other.append(stringConversion[0])
4332            elif numericConversion:
4333                if booleanConversion:
4334                    other.append(CGIfWrapper("value.get().is_boolean()", booleanConversion[0]))
4335                other.append(numericConversion[0])
4336            else:
4337                assert booleanConversion
4338                other.append(booleanConversion[0])
4339            conversions.append(CGList(other, "\n\n"))
4340        conversions.append(CGGeneric(
4341            "throw_not_in_union(cx, \"%s\");\n"
4342            "Err(())" % ", ".join(names)))
4343        method = CGWrapper(
4344            CGIndenter(CGList(conversions, "\n\n")),
4345            pre="unsafe fn from_jsval(cx: *mut JSContext,\n"
4346                "                     value: HandleValue,\n"
4347                "                     _option: ())\n"
4348                "                     -> Result<ConversionResult<%s>, ()> {\n" % self.type,
4349            post="\n}")
4350        return CGWrapper(
4351            CGIndenter(CGList([
4352                CGGeneric("type Config = ();"),
4353                method,
4354            ], "\n")),
4355            pre="impl FromJSValConvertible for %s {\n" % self.type,
4356            post="\n}")
4357
4358    def try_method(self, t):
4359        templateVars = getUnionTypeTemplateVars(t, self.descriptorProvider)
4360        actualType = templateVars["typeName"]
4361        if type_needs_tracing(t):
4362            actualType = "RootedTraceableBox<%s>" % actualType
4363        returnType = "Result<Option<%s>, ()>" % actualType
4364        jsConversion = templateVars["jsConversion"]
4365
4366        # Any code to convert to Object is unused, since we're already converting
4367        # from an Object value.
4368        if t.name == 'Object':
4369            return CGGeneric('')
4370
4371        return CGWrapper(
4372            CGIndenter(jsConversion, 4),
4373            pre="unsafe fn TryConvertTo%s(cx: *mut JSContext, value: HandleValue) -> %s {\n"
4374                % (t.name, returnType),
4375            post="\n}")
4376
4377    def define(self):
4378        from_jsval = self.from_jsval()
4379        methods = CGIndenter(CGList([
4380            self.try_method(t) for t in self.type.flatMemberTypes
4381        ], "\n\n"))
4382        return """
4383%s
4384
4385impl %s {
4386%s
4387}
4388""" % (from_jsval.define(), self.type, methods.define())
4389
4390
4391class ClassItem:
4392    """ Use with CGClass """
4393    def __init__(self, name, visibility):
4394        self.name = name
4395        self.visibility = visibility
4396
4397    def declare(self, cgClass):
4398        assert False
4399
4400    def define(self, cgClass):
4401        assert False
4402
4403
4404class ClassBase(ClassItem):
4405    def __init__(self, name, visibility='pub'):
4406        ClassItem.__init__(self, name, visibility)
4407
4408    def declare(self, cgClass):
4409        return '%s %s' % (self.visibility, self.name)
4410
4411    def define(self, cgClass):
4412        # Only in the header
4413        return ''
4414
4415
4416class ClassMethod(ClassItem):
4417    def __init__(self, name, returnType, args, inline=False, static=False,
4418                 virtual=False, const=False, bodyInHeader=False,
4419                 templateArgs=None, visibility='public', body=None,
4420                 breakAfterReturnDecl="\n", unsafe=False,
4421                 breakAfterSelf="\n", override=False):
4422        """
4423        override indicates whether to flag the method as MOZ_OVERRIDE
4424        """
4425        assert not override or virtual
4426        assert not (override and static)
4427        self.returnType = returnType
4428        self.args = args
4429        self.inline = False
4430        self.static = static
4431        self.virtual = virtual
4432        self.const = const
4433        self.bodyInHeader = True
4434        self.templateArgs = templateArgs
4435        self.body = body
4436        self.breakAfterReturnDecl = breakAfterReturnDecl
4437        self.breakAfterSelf = breakAfterSelf
4438        self.override = override
4439        self.unsafe = unsafe
4440        ClassItem.__init__(self, name, visibility)
4441
4442    def getDecorators(self, declaring):
4443        decorators = []
4444        if self.inline:
4445            decorators.append('inline')
4446        if declaring:
4447            if self.static:
4448                decorators.append('static')
4449            if self.virtual:
4450                decorators.append('virtual')
4451        if decorators:
4452            return ' '.join(decorators) + ' '
4453        return ''
4454
4455    def getBody(self):
4456        # Override me or pass a string to constructor
4457        assert self.body is not None
4458        return self.body
4459
4460    def declare(self, cgClass):
4461        templateClause = '<%s>' % ', '.join(self.templateArgs) \
4462                         if self.bodyInHeader and self.templateArgs else ''
4463        args = ', '.join([a.declare() for a in self.args])
4464        if self.bodyInHeader:
4465            body = CGIndenter(CGGeneric(self.getBody())).define()
4466            body = ' {\n' + body + '\n}'
4467        else:
4468            body = ';'
4469
4470        return string.Template(
4471            "${decorators}%s"
4472            "${visibility}${unsafe}fn ${name}${templateClause}(${args})${returnType}${const}${override}${body}%s" %
4473            (self.breakAfterReturnDecl, self.breakAfterSelf)
4474        ).substitute({
4475            'templateClause': templateClause,
4476            'decorators': self.getDecorators(True),
4477            'returnType': (" -> %s" % self.returnType) if self.returnType else "",
4478            'name': self.name,
4479            'const': ' const' if self.const else '',
4480            'override': ' MOZ_OVERRIDE' if self.override else '',
4481            'args': args,
4482            'body': body,
4483            'visibility': self.visibility + ' ' if self.visibility != 'priv' else '',
4484            'unsafe': "unsafe " if self.unsafe else "",
4485        })
4486
4487    def define(self, cgClass):
4488        pass
4489
4490
4491class ClassConstructor(ClassItem):
4492    """
4493    Used for adding a constructor to a CGClass.
4494
4495    args is a list of Argument objects that are the arguments taken by the
4496    constructor.
4497
4498    inline should be True if the constructor should be marked inline.
4499
4500    bodyInHeader should be True if the body should be placed in the class
4501    declaration in the header.
4502
4503    visibility determines the visibility of the constructor (public,
4504    protected, private), defaults to private.
4505
4506    explicit should be True if the constructor should be marked explicit.
4507
4508    baseConstructors is a list of strings containing calls to base constructors,
4509    defaults to None.
4510
4511    body contains a string with the code for the constructor, defaults to empty.
4512    """
4513    def __init__(self, args, inline=False, bodyInHeader=False,
4514                 visibility="priv", explicit=False, baseConstructors=None,
4515                 body=""):
4516        self.args = args
4517        self.inline = False
4518        self.bodyInHeader = bodyInHeader
4519        self.explicit = explicit
4520        self.baseConstructors = baseConstructors or []
4521        self.body = body
4522        ClassItem.__init__(self, None, visibility)
4523
4524    def getDecorators(self, declaring):
4525        decorators = []
4526        if self.explicit:
4527            decorators.append('explicit')
4528        if self.inline and declaring:
4529            decorators.append('inline')
4530        if decorators:
4531            return ' '.join(decorators) + ' '
4532        return ''
4533
4534    def getInitializationList(self, cgClass):
4535        items = [str(c) for c in self.baseConstructors]
4536        for m in cgClass.members:
4537            if not m.static:
4538                initialize = m.body
4539                if initialize:
4540                    items.append(m.name + "(" + initialize + ")")
4541
4542        if len(items) > 0:
4543            return '\n  : ' + ',\n    '.join(items)
4544        return ''
4545
4546    def getBody(self, cgClass):
4547        initializers = ["    parent: %s" % str(self.baseConstructors[0])]
4548        return (self.body + (
4549                "let mut ret = Rc::new(%s {\n"
4550                "%s\n"
4551                "});\n"
4552                "// Note: callback cannot be moved after calling init.\n"
4553                "match Rc::get_mut(&mut ret) {\n"
4554                "    Some(ref mut callback) => callback.parent.init(%s, %s),\n"
4555                "    None => unreachable!(),\n"
4556                "};\n"
4557                "ret") % (cgClass.name, '\n'.join(initializers),
4558                          self.args[0].name, self.args[1].name))
4559
4560    def declare(self, cgClass):
4561        args = ', '.join([a.declare() for a in self.args])
4562        body = '    ' + self.getBody(cgClass)
4563        body = stripTrailingWhitespace(body.replace('\n', '\n    '))
4564        if len(body) > 0:
4565            body += '\n'
4566        body = ' {\n' + body + '}'
4567
4568        return string.Template("""\
4569pub unsafe fn ${decorators}new(${args}) -> Rc<${className}>${body}
4570""").substitute({'decorators': self.getDecorators(True),
4571                 'className': cgClass.getNameString(),
4572                 'args': args,
4573                 'body': body})
4574
4575    def define(self, cgClass):
4576        if self.bodyInHeader:
4577            return ''
4578
4579        args = ', '.join([a.define() for a in self.args])
4580
4581        body = '    ' + self.getBody()
4582        body = '\n' + stripTrailingWhitespace(body.replace('\n', '\n    '))
4583        if len(body) > 0:
4584            body += '\n'
4585
4586        return string.Template("""\
4587${decorators}
4588${className}::${className}(${args})${initializationList}
4589{${body}}
4590""").substitute({'decorators': self.getDecorators(False),
4591                 'className': cgClass.getNameString(),
4592                 'args': args,
4593                 'initializationList': self.getInitializationList(cgClass),
4594                 'body': body})
4595
4596
4597class ClassMember(ClassItem):
4598    def __init__(self, name, type, visibility="priv", static=False,
4599                 body=None):
4600        self.type = type
4601        self.static = static
4602        self.body = body
4603        ClassItem.__init__(self, name, visibility)
4604
4605    def declare(self, cgClass):
4606        return '%s %s: %s,\n' % (self.visibility, self.name, self.type)
4607
4608    def define(self, cgClass):
4609        if not self.static:
4610            return ''
4611        if self.body:
4612            body = " = " + self.body
4613        else:
4614            body = ""
4615        return '%s %s::%s%s;\n' % (self.type, cgClass.getNameString(),
4616                                   self.name, body)
4617
4618
4619class CGClass(CGThing):
4620    def __init__(self, name, bases=[], members=[], constructors=[],
4621                 destructor=None, methods=[],
4622                 typedefs=[], enums=[], unions=[], templateArgs=[],
4623                 templateSpecialization=[],
4624                 disallowCopyConstruction=False, indent='',
4625                 decorators='',
4626                 extradeclarations=''):
4627        CGThing.__init__(self)
4628        self.name = name
4629        self.bases = bases
4630        self.members = members
4631        self.constructors = constructors
4632        # We store our single destructor in a list, since all of our
4633        # code wants lists of members.
4634        self.destructors = [destructor] if destructor else []
4635        self.methods = methods
4636        self.typedefs = typedefs
4637        self.enums = enums
4638        self.unions = unions
4639        self.templateArgs = templateArgs
4640        self.templateSpecialization = templateSpecialization
4641        self.disallowCopyConstruction = disallowCopyConstruction
4642        self.indent = indent
4643        self.decorators = decorators
4644        self.extradeclarations = extradeclarations
4645
4646    def getNameString(self):
4647        className = self.name
4648        if self.templateSpecialization:
4649            className = className + \
4650                '<%s>' % ', '.join([str(a) for a
4651                                    in self.templateSpecialization])
4652        return className
4653
4654    def define(self):
4655        result = ''
4656        if self.templateArgs:
4657            templateArgs = [a.declare() for a in self.templateArgs]
4658            templateArgs = templateArgs[len(self.templateSpecialization):]
4659            result = result + self.indent + 'template <%s>\n' % ','.join([str(a) for a in templateArgs])
4660
4661        if self.templateSpecialization:
4662            specialization = \
4663                '<%s>' % ', '.join([str(a) for a in self.templateSpecialization])
4664        else:
4665            specialization = ''
4666
4667        myself = ''
4668        if self.decorators != '':
4669            myself += self.decorators + '\n'
4670        myself += '%spub struct %s%s' % (self.indent, self.name, specialization)
4671        result += myself
4672
4673        assert len(self.bases) == 1  # XXjdm Can we support multiple inheritance?
4674
4675        result += ' {\n'
4676
4677        if self.bases:
4678            self.members = [ClassMember("parent", self.bases[0].name, "pub")] + self.members
4679
4680        result += CGIndenter(CGGeneric(self.extradeclarations),
4681                             len(self.indent)).define()
4682
4683        def declareMembers(cgClass, memberList):
4684            result = ''
4685
4686            for member in memberList:
4687                declaration = member.declare(cgClass)
4688                declaration = CGIndenter(CGGeneric(declaration)).define()
4689                result = result + declaration
4690            return result
4691
4692        if self.disallowCopyConstruction:
4693            class DisallowedCopyConstructor(object):
4694                def __init__(self):
4695                    self.visibility = "private"
4696
4697                def declare(self, cgClass):
4698                    name = cgClass.getNameString()
4699                    return ("%s(const %s&) MOZ_DELETE;\n"
4700                            "void operator=(const %s) MOZ_DELETE;\n" % (name, name, name))
4701            disallowedCopyConstructors = [DisallowedCopyConstructor()]
4702        else:
4703            disallowedCopyConstructors = []
4704
4705        order = [(self.enums, ''), (self.unions, ''),
4706                 (self.typedefs, ''), (self.members, '')]
4707
4708        for (memberList, separator) in order:
4709            memberString = declareMembers(self, memberList)
4710            if self.indent:
4711                memberString = CGIndenter(CGGeneric(memberString),
4712                                          len(self.indent)).define()
4713            result = result + memberString
4714
4715        result += self.indent + '}\n\n'
4716        result += 'impl %s {\n' % self.name
4717
4718        order = [(self.constructors + disallowedCopyConstructors, '\n'),
4719                 (self.destructors, '\n'), (self.methods, '\n)')]
4720        for (memberList, separator) in order:
4721            memberString = declareMembers(self, memberList)
4722            if self.indent:
4723                memberString = CGIndenter(CGGeneric(memberString),
4724                                          len(self.indent)).define()
4725            result = result + memberString
4726
4727        result += "}"
4728        return result
4729
4730
4731class CGProxySpecialOperation(CGPerSignatureCall):
4732    """
4733    Base class for classes for calling an indexed or named special operation
4734    (don't use this directly, use the derived classes below).
4735    """
4736    def __init__(self, descriptor, operation):
4737        nativeName = MakeNativeName(descriptor.binaryNameFor(operation))
4738        operation = descriptor.operations[operation]
4739        assert len(operation.signatures()) == 1
4740        signature = operation.signatures()[0]
4741
4742        (returnType, arguments) = signature
4743        if operation.isGetter() and not returnType.nullable():
4744            returnType = IDLNullableType(returnType.location, returnType)
4745
4746        # We pass len(arguments) as the final argument so that the
4747        # CGPerSignatureCall won't do any argument conversion of its own.
4748        CGPerSignatureCall.__init__(self, returnType, "", arguments, nativeName,
4749                                    False, descriptor, operation,
4750                                    len(arguments))
4751
4752        if operation.isSetter() or operation.isCreator():
4753            # arguments[0] is the index or name of the item that we're setting.
4754            argument = arguments[1]
4755            info = getJSToNativeConversionInfo(
4756                argument.type, descriptor, treatNullAs=argument.treatNullAs,
4757                exceptionCode="return false;")
4758            template = info.template
4759            declType = info.declType
4760
4761            templateValues = {
4762                "val": "value.handle()",
4763            }
4764            self.cgRoot.prepend(instantiateJSToNativeConversionTemplate(
4765                template, templateValues, declType, argument.identifier.name))
4766            self.cgRoot.prepend(CGGeneric("rooted!(in(cx) let value = desc.value);"))
4767
4768    def getArguments(self):
4769        args = [(a, process_arg(a.identifier.name, a)) for a in self.arguments]
4770        return args
4771
4772    def wrap_return_value(self):
4773        if not self.idlNode.isGetter() or self.templateValues is None:
4774            return ""
4775
4776        wrap = CGGeneric(wrapForType(**self.templateValues))
4777        wrap = CGIfWrapper("let Some(result) = result", wrap)
4778        return "\n" + wrap.define()
4779
4780
4781class CGProxyIndexedGetter(CGProxySpecialOperation):
4782    """
4783    Class to generate a call to an indexed getter. If templateValues is not None
4784    the returned value will be wrapped with wrapForType using templateValues.
4785    """
4786    def __init__(self, descriptor, templateValues=None):
4787        self.templateValues = templateValues
4788        CGProxySpecialOperation.__init__(self, descriptor, 'IndexedGetter')
4789
4790
4791class CGProxyIndexedSetter(CGProxySpecialOperation):
4792    """
4793    Class to generate a call to an indexed setter.
4794    """
4795    def __init__(self, descriptor):
4796        CGProxySpecialOperation.__init__(self, descriptor, 'IndexedSetter')
4797
4798
4799class CGProxyNamedOperation(CGProxySpecialOperation):
4800    """
4801    Class to generate a call to a named operation.
4802    """
4803    def __init__(self, descriptor, name):
4804        CGProxySpecialOperation.__init__(self, descriptor, name)
4805
4806    def define(self):
4807        # Our first argument is the id we're getting.
4808        argName = self.arguments[0].identifier.name
4809        return ("let %s = jsid_to_string(cx, id).expect(\"Not a string-convertible JSID?\");\n"
4810                "let this = UnwrapProxy(proxy);\n"
4811                "let this = &*this;\n" % argName +
4812                CGProxySpecialOperation.define(self))
4813
4814
4815class CGProxyNamedGetter(CGProxyNamedOperation):
4816    """
4817    Class to generate a call to an named getter. If templateValues is not None
4818    the returned value will be wrapped with wrapForType using templateValues.
4819    """
4820    def __init__(self, descriptor, templateValues=None):
4821        self.templateValues = templateValues
4822        CGProxySpecialOperation.__init__(self, descriptor, 'NamedGetter')
4823
4824
4825class CGProxyNamedPresenceChecker(CGProxyNamedGetter):
4826    """
4827    Class to generate a call that checks whether a named property exists.
4828    For now, we just delegate to CGProxyNamedGetter
4829    """
4830    def __init__(self, descriptor):
4831        CGProxyNamedGetter.__init__(self, descriptor)
4832
4833
4834class CGProxyNamedSetter(CGProxyNamedOperation):
4835    """
4836    Class to generate a call to a named setter.
4837    """
4838    def __init__(self, descriptor):
4839        CGProxySpecialOperation.__init__(self, descriptor, 'NamedSetter')
4840
4841
4842class CGProxyNamedDeleter(CGProxyNamedOperation):
4843    """
4844    Class to generate a call to a named deleter.
4845    """
4846    def __init__(self, descriptor):
4847        CGProxySpecialOperation.__init__(self, descriptor, 'NamedDeleter')
4848
4849
4850class CGProxyUnwrap(CGAbstractMethod):
4851    def __init__(self, descriptor):
4852        args = [Argument('HandleObject', 'obj')]
4853        CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy",
4854                                  '*const ' + descriptor.concreteType, args,
4855                                  alwaysInline=True, unsafe=True)
4856
4857    def definition_body(self):
4858        return CGGeneric("""\
4859/*if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
4860    obj = js::UnwrapObject(obj);
4861}*/
4862//MOZ_ASSERT(IsProxy(obj));
4863let box_ = GetProxyPrivate(obj.get()).to_private() as *const %s;
4864return box_;""" % self.descriptor.concreteType)
4865
4866
4867class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod):
4868    def __init__(self, descriptor):
4869        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
4870                Argument('HandleId', 'id'),
4871                Argument('MutableHandle<PropertyDescriptor>', 'desc')]
4872        CGAbstractExternMethod.__init__(self, descriptor, "getOwnPropertyDescriptor",
4873                                        "bool", args)
4874        self.descriptor = descriptor
4875
4876    # https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty
4877    def getBody(self):
4878        indexedGetter = self.descriptor.operations['IndexedGetter']
4879
4880        get = ""
4881        if indexedGetter:
4882            get = "let index = get_array_index_from_id(cx, id);\n"
4883
4884            attrs = "JSPROP_ENUMERATE"
4885            if self.descriptor.operations['IndexedSetter'] is None:
4886                attrs += " | JSPROP_READONLY"
4887            # FIXME(#11868) Should assign to desc.value, desc.get() is a copy.
4888            fillDescriptor = ("desc.get().value = result_root.get();\n"
4889                              "fill_property_descriptor(desc, proxy.get(), %s);\n"
4890                              "return true;" % attrs)
4891            templateValues = {
4892                'jsvalRef': 'result_root.handle_mut()',
4893                'successCode': fillDescriptor,
4894                'pre': 'rooted!(in(cx) let mut result_root = UndefinedValue());'
4895            }
4896            get += ("if let Some(index) = index {\n" +
4897                    "    let this = UnwrapProxy(proxy);\n" +
4898                    "    let this = &*this;\n" +
4899                    CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" +
4900                    "}\n")
4901
4902        namedGetter = self.descriptor.operations['NamedGetter']
4903        if namedGetter:
4904            attrs = []
4905            if not self.descriptor.interface.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
4906                attrs.append("JSPROP_ENUMERATE")
4907            if self.descriptor.operations['NamedSetter'] is None:
4908                attrs.append("JSPROP_READONLY")
4909            if attrs:
4910                attrs = " | ".join(attrs)
4911            else:
4912                attrs = "0"
4913            # FIXME(#11868) Should assign to desc.value, desc.get() is a copy.
4914            fillDescriptor = ("desc.get().value = result_root.get();\n"
4915                              "fill_property_descriptor(desc, proxy.get(), %s);\n"
4916                              "return true;" % attrs)
4917            templateValues = {
4918                'jsvalRef': 'result_root.handle_mut()',
4919                'successCode': fillDescriptor,
4920                'pre': 'rooted!(in(cx) let mut result_root = UndefinedValue());'
4921            }
4922
4923            # See the similar-looking in CGDOMJSProxyHandler_get for the spec quote.
4924            condition = "RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id)"
4925            if indexedGetter:
4926                condition = "index.is_none() && (%s)" % condition
4927            # Once we start supporting OverrideBuiltins we need to make
4928            # ResolveOwnProperty or EnumerateOwnProperties filter out named
4929            # properties that shadow prototype properties.
4930            namedGet = """
4931if %s {
4932    let mut has_on_proto = false;
4933    if !has_property_on_prototype(cx, proxy, id, &mut has_on_proto) {
4934        return false;
4935    }
4936    if !has_on_proto {
4937        %s
4938    }
4939}
4940""" % (condition, CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues), 8).define())
4941        else:
4942            namedGet = ""
4943
4944        # FIXME(#11868) Should assign to desc.obj, desc.get() is a copy.
4945        return get + """\
4946rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
4947get_expando_object(proxy, expando.handle_mut());
4948//if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
4949if !expando.is_null() {
4950    if !JS_GetPropertyDescriptorById(cx, expando.handle(), id, desc) {
4951        return false;
4952    }
4953    if !desc.obj.is_null() {
4954        // Pretend the property lives on the wrapper.
4955        desc.get().obj = proxy.get();
4956        return true;
4957    }
4958}
4959""" + namedGet + """\
4960desc.get().obj = ptr::null_mut();
4961return true;"""
4962
4963    def definition_body(self):
4964        return CGGeneric(self.getBody())
4965
4966
4967class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod):
4968    def __init__(self, descriptor):
4969        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
4970                Argument('HandleId', 'id'),
4971                Argument('Handle<PropertyDescriptor>', 'desc'),
4972                Argument('*mut ObjectOpResult', 'opresult')]
4973        CGAbstractExternMethod.__init__(self, descriptor, "defineProperty", "bool", args)
4974        self.descriptor = descriptor
4975
4976    def getBody(self):
4977        set = ""
4978
4979        indexedSetter = self.descriptor.operations['IndexedSetter']
4980        if indexedSetter:
4981            set += ("let index = get_array_index_from_id(cx, id);\n" +
4982                    "if let Some(index) = index {\n" +
4983                    "    let this = UnwrapProxy(proxy);\n" +
4984                    "    let this = &*this;\n" +
4985                    CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() +
4986                    "    return (*opresult).succeed();\n" +
4987                    "}\n")
4988        elif self.descriptor.operations['IndexedGetter']:
4989            set += ("if get_array_index_from_id(cx, id).is_some() {\n" +
4990                    "    return (*opresult).failNoIndexedSetter();\n" +
4991                    "}\n")
4992
4993        namedSetter = self.descriptor.operations['NamedSetter']
4994        if namedSetter:
4995            if self.descriptor.hasUnforgeableMembers:
4996                raise TypeError("Can't handle a named setter on an interface that has "
4997                                "unforgeables. Figure out how that should work!")
4998            set += ("if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) {\n" +
4999                    CGIndenter(CGProxyNamedSetter(self.descriptor)).define() +
5000                    "    return (*opresult).succeed();\n" +
5001                    "}\n")
5002        else:
5003            set += ("if RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id) {\n" +
5004                    CGIndenter(CGProxyNamedGetter(self.descriptor)).define() +
5005                    "    if result.is_some() {\n"
5006                    "        return (*opresult).failNoNamedSetter();\n"
5007                    "    }\n"
5008                    "}\n")
5009        set += "return proxyhandler::define_property(%s);" % ", ".join(a.name for a in self.args)
5010        return set
5011
5012    def definition_body(self):
5013        return CGGeneric(self.getBody())
5014
5015
5016class CGDOMJSProxyHandler_delete(CGAbstractExternMethod):
5017    def __init__(self, descriptor):
5018        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
5019                Argument('HandleId', 'id'),
5020                Argument('*mut ObjectOpResult', 'res')]
5021        CGAbstractExternMethod.__init__(self, descriptor, "delete", "bool", args)
5022        self.descriptor = descriptor
5023
5024    def getBody(self):
5025        set = ""
5026        if self.descriptor.operations['NamedDeleter']:
5027            if self.descriptor.hasUnforgeableMembers:
5028                raise TypeError("Can't handle a deleter on an interface that has "
5029                                "unforgeables. Figure out how that should work!")
5030            set += CGProxyNamedDeleter(self.descriptor).define()
5031        set += "return proxyhandler::delete(%s);" % ", ".join(a.name for a in self.args)
5032        return set
5033
5034    def definition_body(self):
5035        return CGGeneric(self.getBody())
5036
5037
5038class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod):
5039    def __init__(self, descriptor):
5040        args = [Argument('*mut JSContext', 'cx'),
5041                Argument('HandleObject', 'proxy'),
5042                Argument('*mut AutoIdVector', 'props')]
5043        CGAbstractExternMethod.__init__(self, descriptor, "own_property_keys", "bool", args)
5044        self.descriptor = descriptor
5045
5046    def getBody(self):
5047        body = dedent(
5048            """
5049            let unwrapped_proxy = UnwrapProxy(proxy);
5050            """)
5051
5052        if self.descriptor.operations['IndexedGetter']:
5053            body += dedent(
5054                """
5055                for i in 0..(*unwrapped_proxy).Length() {
5056                    rooted!(in(cx) let rooted_jsid = int_to_jsid(i as i32));
5057                    AppendToAutoIdVector(props, rooted_jsid.handle().get());
5058                }
5059                """)
5060
5061        if self.descriptor.operations['NamedGetter']:
5062            body += dedent(
5063                """
5064                for name in (*unwrapped_proxy).SupportedPropertyNames() {
5065                    let cstring = CString::new(name).unwrap();
5066                    let jsstring = JS_AtomizeAndPinString(cx, cstring.as_ptr());
5067                    rooted!(in(cx) let rooted = jsstring);
5068                    let jsid = INTERNED_STRING_TO_JSID(cx, rooted.handle().get());
5069                    rooted!(in(cx) let rooted_jsid = jsid);
5070                    AppendToAutoIdVector(props, rooted_jsid.handle().get());
5071                }
5072                """)
5073
5074        body += dedent(
5075            """
5076            rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
5077            get_expando_object(proxy, expando.handle_mut());
5078            if !expando.is_null() {
5079                GetPropertyKeys(cx, expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
5080            }
5081
5082            return true;
5083            """)
5084
5085        return body
5086
5087    def definition_body(self):
5088        return CGGeneric(self.getBody())
5089
5090
5091class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod):
5092    def __init__(self, descriptor):
5093        assert (descriptor.operations["IndexedGetter"] and
5094                descriptor.interface.getExtendedAttribute("LegacyUnenumerableNamedProperties"))
5095        args = [Argument('*mut JSContext', 'cx'),
5096                Argument('HandleObject', 'proxy'),
5097                Argument('*mut AutoIdVector', 'props')]
5098        CGAbstractExternMethod.__init__(self, descriptor,
5099                                        "getOwnEnumerablePropertyKeys", "bool", args)
5100        self.descriptor = descriptor
5101
5102    def getBody(self):
5103        body = dedent(
5104            """
5105            let unwrapped_proxy = UnwrapProxy(proxy);
5106            """)
5107
5108        if self.descriptor.operations['IndexedGetter']:
5109            body += dedent(
5110                """
5111                for i in 0..(*unwrapped_proxy).Length() {
5112                    rooted!(in(cx) let rooted_jsid = int_to_jsid(i as i32));
5113                    AppendToAutoIdVector(props, rooted_jsid.handle().get());
5114                }
5115                """)
5116
5117        body += dedent(
5118            """
5119            rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
5120            get_expando_object(proxy, expando.handle_mut());
5121            if !expando.is_null() {
5122                GetPropertyKeys(cx, expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
5123            }
5124
5125            return true;
5126            """)
5127
5128        return body
5129
5130    def definition_body(self):
5131        return CGGeneric(self.getBody())
5132
5133
5134class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod):
5135    def __init__(self, descriptor):
5136        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
5137                Argument('HandleId', 'id'), Argument('*mut bool', 'bp')]
5138        CGAbstractExternMethod.__init__(self, descriptor, "hasOwn", "bool", args)
5139        self.descriptor = descriptor
5140
5141    def getBody(self):
5142        indexedGetter = self.descriptor.operations['IndexedGetter']
5143        if indexedGetter:
5144            indexed = ("let index = get_array_index_from_id(cx, id);\n" +
5145                       "if let Some(index) = index {\n" +
5146                       "    let this = UnwrapProxy(proxy);\n" +
5147                       "    let this = &*this;\n" +
5148                       CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" +
5149                       "    *bp = result.is_some();\n" +
5150                       "    return true;\n" +
5151                       "}\n\n")
5152        else:
5153            indexed = ""
5154
5155        namedGetter = self.descriptor.operations['NamedGetter']
5156        condition = "RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id)"
5157        if indexedGetter:
5158            condition = "index.is_none() && (%s)" % condition
5159        if namedGetter:
5160            named = """\
5161if %s {
5162    let mut has_on_proto = false;
5163    if !has_property_on_prototype(cx, proxy, id, &mut has_on_proto) {
5164        return false;
5165    }
5166    if !has_on_proto {
5167        %s
5168        *bp = result.is_some();
5169        return true;
5170    }
5171}
5172
5173""" % (condition, CGIndenter(CGProxyNamedGetter(self.descriptor), 8).define())
5174        else:
5175            named = ""
5176
5177        return indexed + """\
5178rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
5179get_expando_object(proxy, expando.handle_mut());
5180if !expando.is_null() {
5181    let ok = JS_HasPropertyById(cx, expando.handle(), id, bp);
5182    if !ok || *bp {
5183        return ok;
5184    }
5185}
5186""" + named + """\
5187*bp = false;
5188return true;"""
5189
5190    def definition_body(self):
5191        return CGGeneric(self.getBody())
5192
5193
5194class CGDOMJSProxyHandler_get(CGAbstractExternMethod):
5195    def __init__(self, descriptor):
5196        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
5197                Argument('HandleValue', 'receiver'), Argument('HandleId', 'id'),
5198                Argument('MutableHandleValue', 'vp')]
5199        CGAbstractExternMethod.__init__(self, descriptor, "get", "bool", args)
5200        self.descriptor = descriptor
5201
5202    # https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty
5203    def getBody(self):
5204        getFromExpando = """\
5205rooted!(in(cx) let mut expando = ptr::null_mut::<JSObject>());
5206get_expando_object(proxy, expando.handle_mut());
5207if !expando.is_null() {
5208    let mut hasProp = false;
5209    if !JS_HasPropertyById(cx, expando.handle(), id, &mut hasProp) {
5210        return false;
5211    }
5212
5213    if hasProp {
5214        return JS_ForwardGetPropertyTo(cx, expando.handle(), id, receiver, vp);
5215    }
5216}"""
5217
5218        templateValues = {
5219            'jsvalRef': 'vp',
5220            'successCode': 'return true;',
5221        }
5222
5223        indexedGetter = self.descriptor.operations['IndexedGetter']
5224        if indexedGetter:
5225            getIndexedOrExpando = ("let index = get_array_index_from_id(cx, id);\n" +
5226                                   "if let Some(index) = index {\n" +
5227                                   "    let this = UnwrapProxy(proxy);\n" +
5228                                   "    let this = &*this;\n" +
5229                                   CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define())
5230            getIndexedOrExpando += """\
5231    // Even if we don't have this index, we don't forward the
5232    // get on to our expando object.
5233} else {
5234    %s
5235}
5236""" % (stripTrailingWhitespace(getFromExpando.replace('\n', '\n    ')))
5237        else:
5238            getIndexedOrExpando = getFromExpando + "\n"
5239
5240        namedGetter = self.descriptor.operations['NamedGetter']
5241        if namedGetter:
5242            condition = "RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id)"
5243            # From step 1:
5244            #     If O supports indexed properties and P is an array index, then:
5245            #
5246            #         3. Set ignoreNamedProps to true.
5247            if indexedGetter:
5248                condition = "index.is_none() && (%s)" % condition
5249            getNamed = ("if %s {\n" +
5250                        CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() +
5251                        "}\n") % condition
5252        else:
5253            getNamed = ""
5254
5255        return """\
5256//MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
5257//"Should not have a XrayWrapper here");
5258
5259%s
5260let mut found = false;
5261if !get_property_on_prototype(cx, proxy, receiver, id, &mut found, vp) {
5262    return false;
5263}
5264
5265if found {
5266    return true;
5267}
5268%s
5269vp.set(UndefinedValue());
5270return true;""" % (getIndexedOrExpando, getNamed)
5271
5272    def definition_body(self):
5273        return CGGeneric(self.getBody())
5274
5275
5276class CGDOMJSProxyHandler_className(CGAbstractExternMethod):
5277    def __init__(self, descriptor):
5278        args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', '_proxy')]
5279        CGAbstractExternMethod.__init__(self, descriptor, "className", "*const i8", args, doesNotPanic=True)
5280        self.descriptor = descriptor
5281
5282    def getBody(self):
5283        return '%s as *const u8 as *const i8' % str_to_const_array(self.descriptor.name)
5284
5285    def definition_body(self):
5286        return CGGeneric(self.getBody())
5287
5288
5289class CGAbstractClassHook(CGAbstractExternMethod):
5290    """
5291    Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw
5292    'this' unwrapping as it assumes that the unwrapped type is always known.
5293    """
5294    def __init__(self, descriptor, name, returnType, args, doesNotPanic=False):
5295        CGAbstractExternMethod.__init__(self, descriptor, name, returnType,
5296                                        args)
5297
5298    def definition_body_prologue(self):
5299        return CGGeneric("""
5300let this = native_from_object::<%s>(obj).unwrap();
5301""" % self.descriptor.concreteType)
5302
5303    def definition_body(self):
5304        return CGList([
5305            self.definition_body_prologue(),
5306            self.generate_code(),
5307        ])
5308
5309    def generate_code(self):
5310        raise NotImplementedError  # Override me!
5311
5312
5313def finalizeHook(descriptor, hookName, context):
5314    release = ""
5315    if descriptor.isGlobal():
5316        release += """\
5317finalize_global(obj);
5318"""
5319    elif descriptor.weakReferenceable:
5320        release += """\
5321let weak_box_ptr = JS_GetReservedSlot(obj, DOM_WEAK_SLOT).to_private() as *mut WeakBox<%s>;
5322if !weak_box_ptr.is_null() {
5323    let count = {
5324        let weak_box = &*weak_box_ptr;
5325        assert!(weak_box.value.get().is_some());
5326        assert!(weak_box.count.get() > 0);
5327        weak_box.value.set(None);
5328        let count = weak_box.count.get() - 1;
5329        weak_box.count.set(count);
5330        count
5331    };
5332    if count == 0 {
5333        mem::drop(Box::from_raw(weak_box_ptr));
5334    }
5335}
5336""" % descriptor.concreteType
5337    release += """\
5338if !this.is_null() {
5339    // The pointer can be null if the object is the unforgeable holder of that interface.
5340    let _ = Box::from_raw(this as *mut %s);
5341}
5342debug!("%s finalize: {:p}", this);\
5343""" % (descriptor.concreteType, descriptor.concreteType)
5344    return release
5345
5346
5347class CGClassTraceHook(CGAbstractClassHook):
5348    """
5349    A hook to trace through our native object; used for GC and CC
5350    """
5351    def __init__(self, descriptor):
5352        args = [Argument('*mut JSTracer', 'trc'), Argument('*mut JSObject', 'obj')]
5353        CGAbstractClassHook.__init__(self, descriptor, TRACE_HOOK_NAME, 'void',
5354                                     args, doesNotPanic=True)
5355        self.traceGlobal = descriptor.isGlobal()
5356
5357    def generate_code(self):
5358        body = [CGGeneric("if this.is_null() { return; } // GC during obj creation\n"
5359                          "(*this).trace(%s);" % self.args[0].name)]
5360        if self.traceGlobal:
5361            body += [CGGeneric("trace_global(trc, obj);")]
5362        return CGList(body, "\n")
5363
5364
5365class CGClassConstructHook(CGAbstractExternMethod):
5366    """
5367    JS-visible constructor for our objects
5368    """
5369    def __init__(self, descriptor, constructor=None):
5370        args = [Argument('*mut JSContext', 'cx'), Argument('u32', 'argc'), Argument('*mut JSVal', 'vp')]
5371        name = CONSTRUCT_HOOK_NAME
5372        if constructor:
5373            name += "_" + constructor.identifier.name
5374        else:
5375            constructor = descriptor.interface.ctor()
5376            assert constructor
5377        CGAbstractExternMethod.__init__(self, descriptor, name, 'bool', args)
5378        self.constructor = constructor
5379        self.exposureSet = descriptor.interface.exposureSet
5380
5381    def definition_body(self):
5382        preamble = """let global = GlobalScope::from_object(JS_CALLEE(cx, vp).to_object());\n"""
5383        if len(self.exposureSet) == 1:
5384            preamble += """\
5385let global = DomRoot::downcast::<dom::types::%s>(global).unwrap();
5386""" % list(self.exposureSet)[0]
5387        preamble += """let args = CallArgs::from_vp(vp, argc);\n"""
5388        preamble = CGGeneric(preamble)
5389        if self.constructor.isHTMLConstructor():
5390            signatures = self.constructor.signatures()
5391            assert len(signatures) == 1
5392            constructorCall = CGGeneric("""\
5393// Step 2 https://html.spec.whatwg.org/multipage/#htmlconstructor
5394// The custom element definition cannot use an element interface as its constructor
5395
5396// The new_target might be a cross-compartment wrapper. Get the underlying object
5397// so we can do the spec's object-identity checks.
5398rooted!(in(cx) let new_target = UnwrapObject(args.new_target().to_object(), 1));
5399if new_target.is_null() {
5400    throw_dom_exception(cx, global.upcast::<GlobalScope>(), Error::Type("new.target is null".to_owned()));
5401    return false;
5402}
5403
5404if args.callee() == new_target.get() {
5405    throw_dom_exception(cx, global.upcast::<GlobalScope>(),
5406        Error::Type("new.target must not be the active function object".to_owned()));
5407    return false;
5408}
5409
5410// Step 6
5411rooted!(in(cx) let mut prototype = ptr::null_mut::<JSObject>());
5412{
5413    rooted!(in(cx) let mut proto_val = UndefinedValue());
5414    let _ac = JSAutoCompartment::new(cx, new_target.get());
5415    if !JS_GetProperty(cx, new_target.handle(), b"prototype\\0".as_ptr() as *const _, proto_val.handle_mut()) {
5416        return false;
5417    }
5418
5419    if !proto_val.is_object() {
5420        // Step 7 of https://html.spec.whatwg.org/multipage/#htmlconstructor.
5421        // This fallback behavior is designed to match analogous behavior for the
5422        // JavaScript built-ins. So we enter the compartment of our underlying
5423        // newTarget object and fall back to the prototype object from that global.
5424        // XXX The spec says to use GetFunctionRealm(), which is not actually
5425        // the same thing as what we have here (e.g. in the case of scripted callable proxies
5426        // whose target is not same-compartment with the proxy, or bound functions, etc).
5427        // https://bugzilla.mozilla.org/show_bug.cgi?id=1317658
5428
5429        rooted!(in(cx) let global_object = CurrentGlobalOrNull(cx));
5430        GetProtoObject(cx, global_object.handle(), prototype.handle_mut());
5431    } else {
5432        // Step 6
5433        prototype.set(proto_val.to_object());
5434    };
5435}
5436
5437// Wrap prototype in this context since it is from the newTarget compartment
5438if !JS_WrapObject(cx, prototype.handle_mut()) {
5439    return false;
5440}
5441
5442let result: Result<DomRoot<%s>, Error> = html_constructor(&global, &args);
5443let result = match result {
5444    Ok(result) => result,
5445    Err(e) => {
5446        throw_dom_exception(cx, global.upcast::<GlobalScope>(), e);
5447        return false;
5448    },
5449};
5450
5451rooted!(in(cx) let mut element = result.reflector().get_jsobject().get());
5452if !JS_WrapObject(cx, element.handle_mut()) {
5453    return false;
5454}
5455
5456JS_SetPrototype(cx, element.handle(), prototype.handle());
5457
5458(result).to_jsval(cx, args.rval());
5459return true;
5460""" % self.descriptor.name)
5461        else:
5462            name = self.constructor.identifier.name
5463            nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
5464            constructorCall = CGMethodCall(["&global"], nativeName, True,
5465                                           self.descriptor, self.constructor)
5466        return CGList([preamble, constructorCall])
5467
5468
5469class CGClassFinalizeHook(CGAbstractClassHook):
5470    """
5471    A hook for finalize, used to release our native object.
5472    """
5473    def __init__(self, descriptor):
5474        args = [Argument('*mut JSFreeOp', '_fop'), Argument('*mut JSObject', 'obj')]
5475        CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
5476                                     'void', args)
5477
5478    def generate_code(self):
5479        return CGGeneric(finalizeHook(self.descriptor, self.name, self.args[0].name))
5480
5481
5482class CGDOMJSProxyHandlerDOMClass(CGThing):
5483    def __init__(self, descriptor):
5484        CGThing.__init__(self)
5485        self.descriptor = descriptor
5486
5487    def define(self):
5488        return "static Class: DOMClass = " + DOMClass(self.descriptor) + ";\n"
5489
5490
5491class CGInterfaceTrait(CGThing):
5492    def __init__(self, descriptor):
5493        CGThing.__init__(self)
5494
5495        def attribute_arguments(needCx, argument=None):
5496            if needCx:
5497                yield "cx", "*mut JSContext"
5498
5499            if argument:
5500                yield "value", argument_type(descriptor, argument)
5501
5502        def members():
5503            for m in descriptor.interface.members:
5504                if (m.isMethod() and not m.isStatic() and
5505                        not m.isMaplikeOrSetlikeOrIterableMethod() and
5506                        (not m.isIdentifierLess() or m.isStringifier())):
5507                    name = CGSpecializedMethod.makeNativeName(descriptor, m)
5508                    infallible = 'infallible' in descriptor.getExtendedAttributes(m)
5509                    for idx, (rettype, arguments) in enumerate(m.signatures()):
5510                        arguments = method_arguments(descriptor, rettype, arguments)
5511                        rettype = return_type(descriptor, rettype, infallible)
5512                        yield name + ('_' * idx), arguments, rettype
5513                elif m.isAttr() and not m.isStatic():
5514                    name = CGSpecializedGetter.makeNativeName(descriptor, m)
5515                    infallible = 'infallible' in descriptor.getExtendedAttributes(m, getter=True)
5516                    yield (name,
5517                           attribute_arguments(typeNeedsCx(m.type, True)),
5518                           return_type(descriptor, m.type, infallible))
5519
5520                    if not m.readonly:
5521                        name = CGSpecializedSetter.makeNativeName(descriptor, m)
5522                        infallible = 'infallible' in descriptor.getExtendedAttributes(m, setter=True)
5523                        if infallible:
5524                            rettype = "()"
5525                        else:
5526                            rettype = "ErrorResult"
5527                        yield name, attribute_arguments(typeNeedsCx(m.type, False), m.type), rettype
5528
5529            if descriptor.proxy:
5530                for name, operation in descriptor.operations.iteritems():
5531                    if not operation or operation.isStringifier():
5532                        continue
5533
5534                    assert len(operation.signatures()) == 1
5535                    rettype, arguments = operation.signatures()[0]
5536
5537                    infallible = 'infallible' in descriptor.getExtendedAttributes(operation)
5538                    if operation.isGetter():
5539                        if not rettype.nullable():
5540                            rettype = IDLNullableType(rettype.location, rettype)
5541                        arguments = method_arguments(descriptor, rettype, arguments)
5542
5543                        # If this interface 'supports named properties', then we
5544                        # should be able to access 'supported property names'
5545                        #
5546                        # WebIDL, Second Draft, section 3.2.4.5
5547                        # https://heycam.github.io/webidl/#idl-named-properties
5548                        if operation.isNamed():
5549                            yield "SupportedPropertyNames", [], "Vec<DOMString>"
5550                    else:
5551                        arguments = method_arguments(descriptor, rettype, arguments)
5552                    rettype = return_type(descriptor, rettype, infallible)
5553                    yield name, arguments, rettype
5554
5555        def fmt(arguments):
5556            return "".join(", %s: %s" % argument for argument in arguments)
5557
5558        def contains_unsafe_arg(arguments):
5559            if not arguments or len(arguments) == 0:
5560                return False
5561            return reduce((lambda x, y: x or y[1] == '*mut JSContext'), arguments, False)
5562
5563        methods = []
5564        for name, arguments, rettype in members():
5565            arguments = list(arguments)
5566            methods.append(CGGeneric("%sfn %s(&self%s) -> %s;\n" % (
5567                'unsafe ' if contains_unsafe_arg(arguments) else '',
5568                name, fmt(arguments), rettype))
5569            )
5570
5571        if methods:
5572            self.cgRoot = CGWrapper(CGIndenter(CGList(methods, "")),
5573                                    pre="pub trait %sMethods {\n" % descriptor.interface.identifier.name,
5574                                    post="}")
5575        else:
5576            self.cgRoot = CGGeneric("")
5577        self.empty = not methods
5578
5579    def define(self):
5580        return self.cgRoot.define()
5581
5582
5583class CGWeakReferenceableTrait(CGThing):
5584    def __init__(self, descriptor):
5585        CGThing.__init__(self)
5586        assert descriptor.weakReferenceable
5587        self.code = "impl WeakReferenceable for %s {}" % descriptor.interface.identifier.name
5588
5589    def define(self):
5590        return self.code
5591
5592
5593def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries=None, enums=None, typedefs=None):
5594    if not callbacks:
5595        callbacks = []
5596    if not dictionaries:
5597        dictionaries = []
5598    if not enums:
5599        enums = []
5600    if not typedefs:
5601        typedefs = []
5602
5603    return CGImports(cgthings, descriptors, callbacks, dictionaries, enums, typedefs, [
5604        'js',
5605        'js::JSCLASS_GLOBAL_SLOT_COUNT',
5606        'js::JSCLASS_IS_DOMJSCLASS',
5607        'js::JSCLASS_IS_GLOBAL',
5608        'js::JSCLASS_RESERVED_SLOTS_MASK',
5609        'js::JS_CALLEE',
5610        'js::error::throw_type_error',
5611        'js::error::throw_internal_error',
5612        'js::jsapi::AutoIdVector',
5613        'js::jsapi::Call',
5614        'js::jsapi::CallArgs',
5615        'js::jsapi::CurrentGlobalOrNull',
5616        'js::jsapi::FreeOp',
5617        'js::jsapi::GetPropertyKeys',
5618        'js::jsapi::GetWellKnownSymbol',
5619        'js::jsapi::Handle',
5620        'js::jsapi::HandleId',
5621        'js::jsapi::HandleObject',
5622        'js::jsapi::HandleValue',
5623        'js::jsapi::HandleValueArray',
5624        'js::jsapi::Heap',
5625        'js::jsapi::INTERNED_STRING_TO_JSID',
5626        'js::jsapi::IsCallable',
5627        'js::jsapi::JSAutoCompartment',
5628        'js::jsapi::JSCLASS_RESERVED_SLOTS_SHIFT',
5629        'js::jsapi::JSClass',
5630        'js::jsapi::JSContext',
5631        'js::jsapi::JSFreeOp',
5632        'js::jsapi::JSFunctionSpec',
5633        'js::jsapi::JSITER_HIDDEN',
5634        'js::jsapi::JSITER_OWNONLY',
5635        'js::jsapi::JSITER_SYMBOLS',
5636        'js::jsapi::JSJitGetterCallArgs',
5637        'js::jsapi::JSJitInfo',
5638        'js::jsapi::JSJitInfo_AliasSet',
5639        'js::jsapi::JSJitInfo_ArgType',
5640        'js::jsapi::JSJitInfo_OpType',
5641        'js::jsapi::JSJitMethodCallArgs',
5642        'js::jsapi::JSJitSetterCallArgs',
5643        'js::jsapi::JSNative',
5644        'js::jsapi::JSNativeWrapper',
5645        'js::jsapi::JSObject',
5646        'js::jsapi::JSPROP_ENUMERATE',
5647        'js::jsapi::JSPROP_PERMANENT',
5648        'js::jsapi::JSPROP_READONLY',
5649        'js::jsapi::JSPROP_SHARED',
5650        'js::jsapi::JSPropertySpec',
5651        'js::jsapi::JSString',
5652        'js::jsapi::JSTracer',
5653        'js::jsapi::JSType',
5654        'js::jsapi::JSTypedMethodJitInfo',
5655        'js::jsapi::JSValueType',
5656        'js::jsapi::JS_AtomizeAndPinString',
5657        'js::jsapi::JS_CallFunctionValue',
5658        'js::jsapi::JS_CopyPropertiesFrom',
5659        'js::jsapi::JS_DefineProperty',
5660        'js::jsapi::JS_DefinePropertyById2',
5661        'js::jsapi::JS_ForwardGetPropertyTo',
5662        'js::jsapi::JS_GetErrorPrototype',
5663        'js::jsapi::JS_GetFunctionPrototype',
5664        'js::jsapi::JS_GetGlobalForObject',
5665        'js::jsapi::JS_GetIteratorPrototype',
5666        'js::jsapi::JS_GetObjectPrototype',
5667        'js::jsapi::JS_GetProperty',
5668        'js::jsapi::JS_GetPropertyById',
5669        'js::jsapi::JS_GetPropertyDescriptorById',
5670        'js::jsapi::JS_GetReservedSlot',
5671        'js::jsapi::JS_HasProperty',
5672        'js::jsapi::JS_HasPropertyById',
5673        'js::jsapi::JS_InitializePropertiesFromCompatibleNativeObject',
5674        'js::jsapi::JS_NewObject',
5675        'js::jsapi::JS_NewObjectWithGivenProto',
5676        'js::jsapi::JS_NewObjectWithoutMetadata',
5677        'js::jsapi::JS_ObjectIsDate',
5678        'js::jsapi::JS_SetImmutablePrototype',
5679        'js::jsapi::JS_SetProperty',
5680        'js::jsapi::JS_SetPrototype',
5681        'js::jsapi::JS_SetReservedSlot',
5682        'js::jsapi::JS_SplicePrototype',
5683        'js::jsapi::JS_WrapValue',
5684        'js::jsapi::JS_WrapObject',
5685        'js::jsapi::MutableHandle',
5686        'js::jsapi::MutableHandleObject',
5687        'js::jsapi::MutableHandleValue',
5688        'js::jsapi::ObjectOpResult',
5689        'js::jsapi::PropertyDescriptor',
5690        'js::jsapi::RootedId',
5691        'js::jsapi::RootedObject',
5692        'js::jsapi::RootedString',
5693        'js::jsapi::SymbolCode',
5694        'js::jsapi::jsid',
5695        'js::jsval::JSVal',
5696        'js::jsval::NullValue',
5697        'js::jsval::ObjectValue',
5698        'js::jsval::ObjectOrNullValue',
5699        'js::jsval::PrivateValue',
5700        'js::jsval::UndefinedValue',
5701        'js::glue::AppendToAutoIdVector',
5702        'js::glue::CallJitGetterOp',
5703        'js::glue::CallJitMethodOp',
5704        'js::glue::CallJitSetterOp',
5705        'js::glue::CreateProxyHandler',
5706        'js::glue::GetProxyPrivate',
5707        'js::glue::NewProxyObject',
5708        'js::glue::ProxyTraps',
5709        'js::glue::RUST_JSID_IS_INT',
5710        'js::glue::RUST_JSID_IS_STRING',
5711        'js::glue::RUST_SYMBOL_TO_JSID',
5712        'js::glue::int_to_jsid',
5713        'js::glue::UnwrapObject',
5714        'js::panic::maybe_resume_unwind',
5715        'js::panic::wrap_panic',
5716        'js::rust::GCMethods',
5717        'js::rust::CustomAutoRooterGuard',
5718        'js::rust::define_methods',
5719        'js::rust::define_properties',
5720        'js::rust::get_object_class',
5721        'dom',
5722        'dom::bindings',
5723        'dom::bindings::codegen::InterfaceObjectMap',
5724        'dom::bindings::constant::ConstantSpec',
5725        'dom::bindings::constant::ConstantVal',
5726        'dom::bindings::interface::ConstructorClassHook',
5727        'dom::bindings::interface::InterfaceConstructorBehavior',
5728        'dom::bindings::interface::NonCallbackInterfaceObjectClass',
5729        'dom::bindings::interface::create_global_object',
5730        'dom::bindings::interface::create_callback_interface_object',
5731        'dom::bindings::interface::create_interface_prototype_object',
5732        'dom::bindings::interface::create_named_constructors',
5733        'dom::bindings::interface::create_noncallback_interface_object',
5734        'dom::bindings::interface::define_guarded_constants',
5735        'dom::bindings::interface::define_guarded_methods',
5736        'dom::bindings::interface::define_guarded_properties',
5737        'dom::bindings::htmlconstructor::html_constructor',
5738        'dom::bindings::interface::is_exposed_in',
5739        'dom::bindings::htmlconstructor::pop_current_element_queue',
5740        'dom::bindings::htmlconstructor::push_new_element_queue',
5741        'dom::bindings::iterable::Iterable',
5742        'dom::bindings::iterable::IteratorType',
5743        'dom::bindings::namespace::NamespaceObjectClass',
5744        'dom::bindings::namespace::create_namespace_object',
5745        'dom::bindings::reflector::MutDomObject',
5746        'dom::bindings::reflector::DomObject',
5747        'dom::bindings::root::Dom',
5748        'dom::bindings::root::DomRoot',
5749        'dom::bindings::root::OptionalHeapSetter',
5750        'dom::bindings::root::RootedReference',
5751        'dom::bindings::utils::AsVoidPtr',
5752        'dom::bindings::utils::DOMClass',
5753        'dom::bindings::utils::DOMJSClass',
5754        'dom::bindings::utils::DOM_PROTO_UNFORGEABLE_HOLDER_SLOT',
5755        'dom::bindings::utils::JSCLASS_DOM_GLOBAL',
5756        'dom::bindings::utils::ProtoOrIfaceArray',
5757        'dom::bindings::utils::enumerate_global',
5758        'dom::bindings::utils::finalize_global',
5759        'dom::bindings::utils::find_enum_value',
5760        'dom::bindings::utils::generic_getter',
5761        'dom::bindings::utils::generic_lenient_getter',
5762        'dom::bindings::utils::generic_lenient_setter',
5763        'dom::bindings::utils::generic_method',
5764        'dom::bindings::utils::generic_setter',
5765        'dom::bindings::utils::get_array_index_from_id',
5766        'dom::bindings::utils::get_dictionary_property',
5767        'dom::bindings::utils::get_property_on_prototype',
5768        'dom::bindings::utils::get_proto_or_iface_array',
5769        'dom::bindings::utils::has_property_on_prototype',
5770        'dom::bindings::utils::is_platform_object',
5771        'dom::bindings::utils::resolve_global',
5772        'dom::bindings::utils::set_dictionary_property',
5773        'dom::bindings::utils::trace_global',
5774        'dom::bindings::trace::JSTraceable',
5775        'dom::bindings::trace::RootedTraceable',
5776        'dom::bindings::trace::RootedTraceableBox',
5777        'dom::bindings::callback::CallSetup',
5778        'dom::bindings::callback::CallbackContainer',
5779        'dom::bindings::callback::CallbackInterface',
5780        'dom::bindings::callback::CallbackFunction',
5781        'dom::bindings::callback::CallbackObject',
5782        'dom::bindings::callback::ExceptionHandling',
5783        'dom::bindings::callback::wrap_call_this_object',
5784        'dom::bindings::conversions::ConversionBehavior',
5785        'dom::bindings::conversions::ConversionResult',
5786        'dom::bindings::conversions::DOM_OBJECT_SLOT',
5787        'dom::bindings::conversions::FromJSValConvertible',
5788        'dom::bindings::conversions::IDLInterface',
5789        'dom::bindings::conversions::StringificationBehavior',
5790        'dom::bindings::conversions::ToJSValConvertible',
5791        'dom::bindings::conversions::is_array_like',
5792        'dom::bindings::conversions::native_from_handlevalue',
5793        'dom::bindings::conversions::native_from_object',
5794        'dom::bindings::conversions::private_from_object',
5795        'dom::bindings::conversions::root_from_handleobject',
5796        'dom::bindings::conversions::root_from_handlevalue',
5797        'dom::bindings::conversions::root_from_object',
5798        'dom::bindings::conversions::jsid_to_string',
5799        'dom::bindings::codegen::PrototypeList',
5800        'dom::bindings::codegen::RegisterBindings',
5801        'dom::bindings::codegen::UnionTypes',
5802        'dom::bindings::error::Error',
5803        'dom::bindings::error::ErrorResult',
5804        'dom::bindings::error::Fallible',
5805        'dom::bindings::error::Error::JSFailed',
5806        'dom::bindings::error::throw_dom_exception',
5807        'dom::bindings::guard::Condition',
5808        'dom::bindings::guard::Guard',
5809        'dom::bindings::inheritance::Castable',
5810        'dom::bindings::proxyhandler',
5811        'dom::bindings::proxyhandler::ensure_expando_object',
5812        'dom::bindings::proxyhandler::fill_property_descriptor',
5813        'dom::bindings::proxyhandler::get_expando_object',
5814        'dom::bindings::proxyhandler::get_property_descriptor',
5815        'dom::bindings::mozmap::MozMap',
5816        'std::ptr::NonNull',
5817        'dom::bindings::num::Finite',
5818        'dom::bindings::str::ByteString',
5819        'dom::bindings::str::DOMString',
5820        'dom::bindings::str::USVString',
5821        'dom::bindings::weakref::DOM_WEAK_SLOT',
5822        'dom::bindings::weakref::WeakBox',
5823        'dom::bindings::weakref::WeakReferenceable',
5824        'dom::windowproxy::WindowProxy',
5825        'dom::globalscope::GlobalScope',
5826        'mem::malloc_size_of_including_raw_self',
5827        'libc',
5828        'servo_config::prefs::PREFS',
5829        'std::borrow::ToOwned',
5830        'std::cmp',
5831        'std::mem',
5832        'std::num',
5833        'std::os',
5834        'std::panic',
5835        'std::ptr',
5836        'std::str',
5837        'std::rc',
5838        'std::rc::Rc',
5839        'std::default::Default',
5840        'std::ffi::CString',
5841    ], config)
5842
5843
5844class CGDescriptor(CGThing):
5845    def __init__(self, descriptor, config, soleDescriptor):
5846        CGThing.__init__(self)
5847
5848        assert not descriptor.concrete or not descriptor.interface.isCallback()
5849
5850        reexports = []
5851
5852        def reexportedName(name):
5853            if name.startswith(descriptor.name):
5854                return name
5855            if not soleDescriptor:
5856                return '%s as %s%s' % (name, descriptor.name, name)
5857            return name
5858
5859        cgThings = []
5860
5861        unscopableNames = []
5862        for m in descriptor.interface.members:
5863            if (m.isMethod() and
5864                    (not m.isIdentifierLess() or m == descriptor.operations["Stringifier"])):
5865                if m.getExtendedAttribute("Unscopable"):
5866                    assert not m.isStatic()
5867                    unscopableNames.append(m.identifier.name)
5868                if m.isStatic():
5869                    assert descriptor.interface.hasInterfaceObject()
5870                    cgThings.append(CGStaticMethod(descriptor, m))
5871                elif not descriptor.interface.isCallback():
5872                    cgThings.append(CGSpecializedMethod(descriptor, m))
5873                    cgThings.append(CGMemberJITInfo(descriptor, m))
5874            elif m.isAttr():
5875                if m.stringifier:
5876                    raise TypeError("Stringifier attributes not supported yet. "
5877                                    "See https://github.com/servo/servo/issues/7590\n"
5878                                    "%s" % m.location)
5879                if m.getExtendedAttribute("Unscopable"):
5880                    assert not m.isStatic()
5881                    unscopableNames.append(m.identifier.name)
5882                if m.isStatic():
5883                    assert descriptor.interface.hasInterfaceObject()
5884                    cgThings.append(CGStaticGetter(descriptor, m))
5885                elif not descriptor.interface.isCallback():
5886                    cgThings.append(CGSpecializedGetter(descriptor, m))
5887
5888                if not m.readonly:
5889                    if m.isStatic():
5890                        assert descriptor.interface.hasInterfaceObject()
5891                        cgThings.append(CGStaticSetter(descriptor, m))
5892                    elif not descriptor.interface.isCallback():
5893                        cgThings.append(CGSpecializedSetter(descriptor, m))
5894                elif m.getExtendedAttribute("PutForwards"):
5895                    cgThings.append(CGSpecializedForwardingSetter(descriptor, m))
5896                elif m.getExtendedAttribute("Replaceable"):
5897                    cgThings.append(CGSpecializedReplaceableSetter(descriptor, m))
5898
5899                if (not m.isStatic() and not descriptor.interface.isCallback()):
5900                    cgThings.append(CGMemberJITInfo(descriptor, m))
5901
5902        if descriptor.concrete:
5903            cgThings.append(CGClassFinalizeHook(descriptor))
5904            cgThings.append(CGClassTraceHook(descriptor))
5905
5906        # If there are no constant members, don't make a module for constants
5907        constMembers = [CGConstant(m) for m in descriptor.interface.members if m.isConst()]
5908        if constMembers:
5909            cgThings.append(CGNamespace.build([descriptor.name + "Constants"],
5910                                              CGIndenter(CGList(constMembers)),
5911                                              public=True))
5912            reexports.append(descriptor.name + 'Constants')
5913
5914        if descriptor.proxy:
5915            cgThings.append(CGDefineProxyHandler(descriptor))
5916
5917        properties = PropertyArrays(descriptor)
5918
5919        if descriptor.concrete:
5920            if descriptor.proxy:
5921                # cgThings.append(CGProxyIsProxy(descriptor))
5922                cgThings.append(CGProxyUnwrap(descriptor))
5923                cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor))
5924                cgThings.append(CGDOMJSProxyHandler_ownPropertyKeys(descriptor))
5925                if descriptor.interface.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
5926                    cgThings.append(CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(descriptor))
5927                cgThings.append(CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor))
5928                cgThings.append(CGDOMJSProxyHandler_className(descriptor))
5929                cgThings.append(CGDOMJSProxyHandler_get(descriptor))
5930                cgThings.append(CGDOMJSProxyHandler_hasOwn(descriptor))
5931
5932                if descriptor.operations['IndexedSetter'] or descriptor.operations['NamedSetter']:
5933                    cgThings.append(CGDOMJSProxyHandler_defineProperty(descriptor))
5934
5935                # We want to prevent indexed deleters from compiling at all.
5936                assert not descriptor.operations['IndexedDeleter']
5937
5938                if descriptor.operations['NamedDeleter']:
5939                    cgThings.append(CGDOMJSProxyHandler_delete(descriptor))
5940
5941                # cgThings.append(CGDOMJSProxyHandler(descriptor))
5942                # cgThings.append(CGIsMethod(descriptor))
5943                pass
5944            else:
5945                cgThings.append(CGDOMJSClass(descriptor))
5946                pass
5947
5948            if descriptor.isGlobal():
5949                cgThings.append(CGWrapGlobalMethod(descriptor, properties))
5950            else:
5951                cgThings.append(CGWrapMethod(descriptor))
5952            reexports.append('Wrap')
5953
5954        haveUnscopables = False
5955        if not descriptor.interface.isCallback() and not descriptor.interface.isNamespace():
5956            if unscopableNames:
5957                haveUnscopables = True
5958                cgThings.append(
5959                    CGList([CGGeneric("const unscopable_names: &'static [&'static [u8]] = &["),
5960                            CGIndenter(CGList([CGGeneric(str_to_const_array(name)) for
5961                                               name in unscopableNames], ",\n")),
5962                            CGGeneric("];\n")], "\n"))
5963            if descriptor.concrete or descriptor.hasDescendants():
5964                cgThings.append(CGIDLInterface(descriptor))
5965
5966            interfaceTrait = CGInterfaceTrait(descriptor)
5967            cgThings.append(interfaceTrait)
5968            if not interfaceTrait.empty:
5969                reexports.append('%sMethods' % descriptor.name)
5970
5971            if descriptor.weakReferenceable:
5972                cgThings.append(CGWeakReferenceableTrait(descriptor))
5973
5974        cgThings.append(CGGeneric(str(properties)))
5975
5976        if not descriptor.interface.getExtendedAttribute("Inline"):
5977            if not descriptor.interface.isCallback() and not descriptor.interface.isNamespace():
5978                cgThings.append(CGGetProtoObjectMethod(descriptor))
5979                reexports.append('GetProtoObject')
5980                cgThings.append(CGPrototypeJSClass(descriptor))
5981            if descriptor.interface.hasInterfaceObject():
5982                if descriptor.interface.ctor():
5983                    cgThings.append(CGClassConstructHook(descriptor))
5984                for ctor in descriptor.interface.namedConstructors:
5985                    cgThings.append(CGClassConstructHook(descriptor, ctor))
5986                if not descriptor.interface.isCallback():
5987                    cgThings.append(CGInterfaceObjectJSClass(descriptor))
5988                if descriptor.shouldHaveGetConstructorObjectMethod():
5989                    cgThings.append(CGGetConstructorObjectMethod(descriptor))
5990                    reexports.append('GetConstructorObject')
5991                if descriptor.register:
5992                    cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
5993                    reexports.append('DefineDOMInterface')
5994                    cgThings.append(CGConstructorEnabled(descriptor))
5995            cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties, haveUnscopables))
5996
5997        cgThings = generate_imports(config, CGList(cgThings, '\n'), [descriptor])
5998        cgThings = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name),
5999                                         cgThings, public=True),
6000                             post='\n')
6001
6002        if reexports:
6003            reexports = ', '.join(map(lambda name: reexportedName(name), reexports))
6004            cgThings = CGList([CGGeneric('pub use self::%s::{%s};' % (toBindingNamespace(descriptor.name), reexports)),
6005                               cgThings], '\n')
6006
6007        self.cgRoot = cgThings
6008
6009    def define(self):
6010        return self.cgRoot.define()
6011
6012
6013class CGNonNamespacedEnum(CGThing):
6014    def __init__(self, enumName, names, first, comment="", deriving="", repr=""):
6015        # Account for first value
6016        entries = ["%s = %s" % (names[0], first)] + names[1:]
6017
6018        # Append a Last.
6019        entries.append('#[allow(dead_code)] Last = ' + str(first + len(entries)))
6020
6021        # Indent.
6022        entries = ['    ' + e for e in entries]
6023
6024        # Build the enum body.
6025        enumstr = comment + 'pub enum %s {\n%s\n}\n' % (enumName, ',\n'.join(entries))
6026        if repr:
6027            enumstr = ('#[repr(%s)]\n' % repr) + enumstr
6028        if deriving:
6029            enumstr = ('#[derive(%s)]\n' % deriving) + enumstr
6030        curr = CGGeneric(enumstr)
6031
6032        # Add some whitespace padding.
6033        curr = CGWrapper(curr, pre='\n', post='\n')
6034
6035        # Add the typedef
6036        # typedef = '\ntypedef %s::%s %s;\n\n' % (namespace, enumName, enumName)
6037        # curr = CGList([curr, CGGeneric(typedef)])
6038
6039        # Save the result.
6040        self.node = curr
6041
6042    def define(self):
6043        return self.node.define()
6044
6045
6046class CGDictionary(CGThing):
6047    def __init__(self, dictionary, descriptorProvider):
6048        self.dictionary = dictionary
6049        if all(CGDictionary(d, descriptorProvider).generatable for
6050               d in CGDictionary.getDictionaryDependencies(dictionary)):
6051            self.generatable = True
6052        else:
6053            self.generatable = False
6054            # Nothing else to do here
6055            return
6056
6057        self.memberInfo = [
6058            (member,
6059             getJSToNativeConversionInfo(member.type,
6060                                         descriptorProvider,
6061                                         isMember="Dictionary",
6062                                         defaultValue=member.defaultValue,
6063                                         exceptionCode="return Err(());"))
6064            for member in dictionary.members]
6065
6066    def define(self):
6067        if not self.generatable:
6068            return ""
6069        return self.struct() + "\n" + self.impl()
6070
6071    def struct(self):
6072        d = self.dictionary
6073        if d.parent:
6074            inheritance = "    pub parent: %s::%s,\n" % (self.makeModuleName(d.parent),
6075                                                         self.makeClassName(d.parent))
6076        else:
6077            inheritance = ""
6078        memberDecls = ["    pub %s: %s," %
6079                       (self.makeMemberName(m[0].identifier.name), self.getMemberType(m))
6080                       for m in self.memberInfo]
6081
6082        derive = ["JSTraceable"]
6083        mustRoot = ""
6084        if self.membersNeedTracing():
6085            mustRoot = "#[must_root]\n"
6086            derive += ["Default"]
6087
6088        return (string.Template(
6089                "#[derive(${derive})]\n"
6090                "${mustRoot}" +
6091                "pub struct ${selfName} {\n" +
6092                "${inheritance}" +
6093                "\n".join(memberDecls) + "\n" +
6094                "}").substitute({"selfName": self.makeClassName(d),
6095                                 "inheritance": inheritance,
6096                                 "mustRoot": mustRoot,
6097                                 "derive": ', '.join(derive)}))
6098
6099    def impl(self):
6100        d = self.dictionary
6101        if d.parent:
6102            initParent = ("{\n"
6103                          "    match try!(%s::%s::new(cx, val)) {\n"
6104                          "        ConversionResult::Success(v) => v,\n"
6105                          "        ConversionResult::Failure(error) => {\n"
6106                          "            throw_type_error(cx, &error);\n"
6107                          "            return Err(());\n"
6108                          "        }\n"
6109                          "    }\n"
6110                          "}" % (self.makeModuleName(d.parent),
6111                                 self.makeClassName(d.parent)))
6112        else:
6113            initParent = ""
6114
6115        def memberInit(memberInfo, isInitial):
6116            member, _ = memberInfo
6117            name = self.makeMemberName(member.identifier.name)
6118            conversion = self.getMemberConversion(memberInfo, member.type)
6119            if isInitial:
6120                return CGGeneric("%s: %s,\n" % (name, conversion.define()))
6121            if member.type.isAny() or member.type.isObject():
6122                return CGGeneric("dictionary.%s.set(%s);\n" % (name, conversion.define()))
6123            return CGGeneric("dictionary.%s = %s;\n" % (name, conversion.define()))
6124
6125        def varInsert(varName, dictionaryName):
6126            insertion = ("rooted!(in(cx) let mut %s_js = UndefinedValue());\n"
6127                         "%s.to_jsval(cx, %s_js.handle_mut());\n"
6128                         "set_dictionary_property(cx, obj.handle(), \"%s\", %s_js.handle()).unwrap();"
6129                         % (varName, varName, varName, dictionaryName, varName))
6130            return CGGeneric(insertion)
6131
6132        def memberInsert(memberInfo):
6133            member, _ = memberInfo
6134            name = self.makeMemberName(member.identifier.name)
6135            if member.optional and not member.defaultValue:
6136                insertion = CGIfWrapper("let Some(ref %s) = self.%s" % (name, name),
6137                                        varInsert(name, member.identifier.name))
6138            else:
6139                insertion = CGGeneric("let %s = &self.%s;\n%s" %
6140                                      (name, name, varInsert(name, member.identifier.name).define()))
6141            return CGGeneric("%s\n" % insertion.define())
6142
6143        memberInserts = CGList([memberInsert(m) for m in self.memberInfo])
6144
6145        selfName = self.makeClassName(d)
6146        if self.membersNeedTracing():
6147            actualType = "RootedTraceableBox<%s>" % selfName
6148            preInitial = "let mut dictionary = RootedTraceableBox::new(%s::default());\n" % selfName
6149            initParent = initParent = ("dictionary.parent = %s;\n" % initParent) if initParent else ""
6150            memberInits = CGList([memberInit(m, False) for m in self.memberInfo])
6151            postInitial = ""
6152        else:
6153            actualType = selfName
6154            preInitial = "let dictionary = %s {\n" % selfName
6155            postInitial = "};\n"
6156            initParent = ("parent: %s,\n" % initParent) if initParent else ""
6157            memberInits = CGList([memberInit(m, True) for m in self.memberInfo])
6158
6159        return string.Template(
6160            "impl ${selfName} {\n"
6161            "    pub unsafe fn empty(cx: *mut JSContext) -> ${actualType} {\n"
6162            "        match ${selfName}::new(cx, HandleValue::null()) {\n"
6163            "            Ok(ConversionResult::Success(v)) => v,\n"
6164            "            _ => unreachable!(),\n"
6165            "        }\n"
6166            "    }\n"
6167            "    pub unsafe fn new(cx: *mut JSContext, val: HandleValue) \n"
6168            "                      -> Result<ConversionResult<${actualType}>, ()> {\n"
6169            "        let object = if val.get().is_null_or_undefined() {\n"
6170            "            ptr::null_mut()\n"
6171            "        } else if val.get().is_object() {\n"
6172            "            val.get().to_object()\n"
6173            "        } else {\n"
6174            "            return Ok(ConversionResult::Failure(\"Value is not an object.\".into()));\n"
6175            "        };\n"
6176            "        rooted!(in(cx) let object = object);\n"
6177            "${preInitial}"
6178            "${initParent}"
6179            "${initMembers}"
6180            "${postInitial}"
6181            "        Ok(ConversionResult::Success(dictionary))\n"
6182            "    }\n"
6183            "}\n"
6184            "\n"
6185            "impl FromJSValConvertible for ${actualType} {\n"
6186            "    type Config = ();\n"
6187            "    unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, _option: ())\n"
6188            "                         -> Result<ConversionResult<${actualType}>, ()> {\n"
6189            "        ${selfName}::new(cx, value)\n"
6190            "    }\n"
6191            "}\n"
6192            "\n"
6193            "impl ToJSValConvertible for ${selfName} {\n"
6194            "    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {\n"
6195            "        rooted!(in(cx) let obj = JS_NewObject(cx, ptr::null()));\n"
6196            "${insertMembers}"
6197            "        rval.set(ObjectOrNullValue(obj.get()))\n"
6198            "    }\n"
6199            "}\n").substitute({
6200                "selfName": selfName,
6201                "actualType": actualType,
6202                "initParent": CGIndenter(CGGeneric(initParent), indentLevel=12).define(),
6203                "initMembers": CGIndenter(memberInits, indentLevel=12).define(),
6204                "insertMembers": CGIndenter(memberInserts, indentLevel=8).define(),
6205                "preInitial": CGIndenter(CGGeneric(preInitial), indentLevel=12).define(),
6206                "postInitial": CGIndenter(CGGeneric(postInitial), indentLevel=12).define(),
6207            })
6208
6209    def membersNeedTracing(self):
6210        for member, _ in self.memberInfo:
6211            if type_needs_tracing(member.type):
6212                return True
6213        return False
6214
6215    @staticmethod
6216    def makeDictionaryName(dictionary):
6217        return dictionary.identifier.name
6218
6219    def makeClassName(self, dictionary):
6220        return self.makeDictionaryName(dictionary)
6221
6222    @staticmethod
6223    def makeModuleName(dictionary):
6224        return getModuleFromObject(dictionary)
6225
6226    def getMemberType(self, memberInfo):
6227        member, info = memberInfo
6228        declType = info.declType
6229        if member.optional and not member.defaultValue:
6230            declType = CGWrapper(info.declType, pre="Option<", post=">")
6231        return declType.define()
6232
6233    def getMemberConversion(self, memberInfo, memberType):
6234        def indent(s):
6235            return CGIndenter(CGGeneric(s), 12).define()
6236
6237        member, info = memberInfo
6238        templateBody = info.template
6239        default = info.default
6240        replacements = {"val": "rval.handle()"}
6241        conversion = string.Template(templateBody).substitute(replacements)
6242
6243        assert (member.defaultValue is None) == (default is None)
6244        if not member.optional:
6245            assert default is None
6246            default = ("throw_type_error(cx, \"Missing required member \\\"%s\\\".\");\n"
6247                       "return Err(());") % member.identifier.name
6248        elif not default:
6249            default = "None"
6250            conversion = "Some(%s)" % conversion
6251
6252        conversion = (
6253            "{\n"
6254            "    rooted!(in(cx) let mut rval = UndefinedValue());\n"
6255            "    match try!(get_dictionary_property(cx, object.handle(), \"%s\", rval.handle_mut())) {\n"
6256            "        true => {\n"
6257            "%s\n"
6258            "        },\n"
6259            "        false => {\n"
6260            "%s\n"
6261            "        },\n"
6262            "    }\n"
6263            "}") % (member.identifier.name, indent(conversion), indent(default))
6264
6265        return CGGeneric(conversion)
6266
6267    @staticmethod
6268    def makeMemberName(name):
6269        # Can't use Rust keywords as member names.
6270        if name in RUST_KEYWORDS:
6271            return name + "_"
6272        return name
6273
6274    @staticmethod
6275    def getDictionaryDependencies(dictionary):
6276        deps = set()
6277        if dictionary.parent:
6278            deps.add(dictionary.parent)
6279        for member in dictionary.members:
6280            if member.type.isDictionary():
6281                deps.add(member.type.unroll().inner)
6282        return deps
6283
6284
6285class CGRegisterProxyHandlersMethod(CGAbstractMethod):
6286    def __init__(self, descriptors):
6287        docs = "Create the global vtables used by the generated DOM bindings to implement JS proxies."
6288        CGAbstractMethod.__init__(self, None, 'RegisterProxyHandlers', 'void', [],
6289                                  unsafe=True, pub=True, docs=docs)
6290        self.descriptors = descriptors
6291
6292    def definition_body(self):
6293        return CGList([
6294            CGGeneric("PROXY_HANDLERS[Proxies::%s as usize] = Bindings::%s::DefineProxyHandler();"
6295                      % (desc.name, '::'.join([desc.name + 'Binding'] * 2)))
6296            for desc in self.descriptors
6297        ], "\n")
6298
6299
6300class CGRegisterProxyHandlers(CGThing):
6301    def __init__(self, config):
6302        descriptors = config.getDescriptors(proxy=True)
6303        length = len(descriptors)
6304        self.root = CGList([
6305            CGGeneric("pub static mut PROXY_HANDLERS: [*const libc::c_void; %d] = [0 as *const libc::c_void; %d];"
6306                      % (length, length)),
6307            CGRegisterProxyHandlersMethod(descriptors),
6308        ], "\n")
6309
6310    def define(self):
6311        return self.root.define()
6312
6313
6314class CGBindingRoot(CGThing):
6315    """
6316    DomRoot codegen class for binding generation. Instantiate the class, and call
6317    declare or define to generate header or cpp code (respectively).
6318    """
6319    def __init__(self, config, prefix, webIDLFile):
6320        descriptors = config.getDescriptors(webIDLFile=webIDLFile,
6321                                            hasInterfaceObject=True)
6322        # We also want descriptors that have an interface prototype object
6323        # (isCallback=False), but we don't want to include a second copy
6324        # of descriptors that we also matched in the previous line
6325        # (hence hasInterfaceObject=False).
6326        descriptors.extend(config.getDescriptors(webIDLFile=webIDLFile,
6327                                                 hasInterfaceObject=False,
6328                                                 isCallback=False,
6329                                                 register=True))
6330
6331        dictionaries = config.getDictionaries(webIDLFile=webIDLFile)
6332
6333        mainCallbacks = config.getCallbacks(webIDLFile=webIDLFile)
6334        callbackDescriptors = config.getDescriptors(webIDLFile=webIDLFile,
6335                                                    isCallback=True)
6336
6337        enums = config.getEnums(webIDLFile)
6338        typedefs = config.getTypedefs(webIDLFile)
6339
6340        if not (descriptors or dictionaries or mainCallbacks or callbackDescriptors or enums):
6341            self.root = None
6342            return
6343
6344        # Do codegen for all the enums.
6345        cgthings = [CGEnum(e) for e in enums]
6346
6347        # Do codegen for all the typedefs
6348        for t in typedefs:
6349            typeName = getRetvalDeclarationForType(t.innerType, config.getDescriptorProvider())
6350            substs = {
6351                "name": t.identifier.name,
6352                "type": typeName.define(),
6353            }
6354
6355            if t.innerType.isUnion() and not t.innerType.nullable():
6356                # Allow using the typedef's name for accessing variants.
6357                template = "pub use self::%(type)s as %(name)s;"
6358            else:
6359                template = "pub type %(name)s = %(type)s;"
6360
6361            cgthings.append(CGGeneric(template % substs))
6362
6363        # Do codegen for all the dictionaries.
6364        cgthings.extend([CGDictionary(d, config.getDescriptorProvider())
6365                         for d in dictionaries])
6366
6367        # Do codegen for all the callbacks.
6368        cgthings.extend(CGList([CGCallbackFunction(c, config.getDescriptorProvider()),
6369                                CGCallbackFunctionImpl(c)], "\n")
6370                        for c in mainCallbacks)
6371
6372        # Do codegen for all the descriptors
6373        cgthings.extend([CGDescriptor(x, config, len(descriptors) == 1) for x in descriptors])
6374
6375        # Do codegen for all the callback interfaces.
6376        cgthings.extend(CGList([CGCallbackInterface(x),
6377                                CGCallbackFunctionImpl(x.interface)], "\n")
6378                        for x in callbackDescriptors)
6379
6380        # And make sure we have the right number of newlines at the end
6381        curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n")
6382
6383        # Add imports
6384        curr = generate_imports(config, curr, callbackDescriptors, mainCallbacks,
6385                                dictionaries, enums, typedefs)
6386
6387        # Add the auto-generated comment.
6388        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
6389
6390        # Store the final result.
6391        self.root = curr
6392
6393    def define(self):
6394        if not self.root:
6395            return None
6396        return stripTrailingWhitespace(self.root.define())
6397
6398
6399def type_needs_tracing(t):
6400    assert isinstance(t, IDLObject), (t, type(t))
6401
6402    if t.isType():
6403        if isinstance(t, IDLWrapperType):
6404            return type_needs_tracing(t.inner)
6405
6406        if t.nullable():
6407            return type_needs_tracing(t.inner)
6408
6409        if t.isAny():
6410            return True
6411
6412        if t.isObject():
6413            return True
6414
6415        if t.isSequence():
6416            return type_needs_tracing(t.inner)
6417
6418        if t.isUnion():
6419            return any(type_needs_tracing(member) for member in t.flatMemberTypes)
6420
6421        return False
6422
6423    if t.isDictionary():
6424        if t.parent and type_needs_tracing(t.parent):
6425            return True
6426
6427        if any(type_needs_tracing(member.type) for member in t.members):
6428            return True
6429
6430        return False
6431
6432    if t.isInterface():
6433        return False
6434
6435    if t.isEnum():
6436        return False
6437
6438    assert False, (t, type(t))
6439
6440
6441def type_needs_auto_root(t):
6442    """
6443    Certain IDL types, such as `sequence<any>` or `sequence<object>` need to be
6444    traced and wrapped via (Custom)AutoRooter
6445    """
6446    assert isinstance(t, IDLObject), (t, type(t))
6447
6448    if t.isType():
6449        if t.isSequence() and (t.inner.isAny() or t.inner.isObject()):
6450            return True
6451
6452    return False
6453
6454
6455def argument_type(descriptorProvider, ty, optional=False, defaultValue=None, variadic=False):
6456    info = getJSToNativeConversionInfo(
6457        ty, descriptorProvider, isArgument=True,
6458        isAutoRooted=type_needs_auto_root(ty))
6459    declType = info.declType
6460
6461    if variadic:
6462        if ty.isGeckoInterface():
6463            declType = CGWrapper(declType, pre="&[", post="]")
6464        else:
6465            declType = CGWrapper(declType, pre="Vec<", post=">")
6466    elif optional and not defaultValue:
6467        declType = CGWrapper(declType, pre="Option<", post=">")
6468
6469    if ty.isDictionary() and not type_needs_tracing(ty):
6470        declType = CGWrapper(declType, pre="&")
6471
6472    if type_needs_auto_root(ty):
6473        declType = CGTemplatedType("CustomAutoRooterGuard", declType)
6474
6475    return declType.define()
6476
6477
6478def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True, trailing=None):
6479    if needCx(returnType, arguments, passJSBits):
6480        yield "cx", "*mut JSContext"
6481
6482    for argument in arguments:
6483        ty = argument_type(descriptorProvider, argument.type, argument.optional,
6484                           argument.defaultValue, argument.variadic)
6485        yield CGDictionary.makeMemberName(argument.identifier.name), ty
6486
6487    if trailing:
6488        yield trailing
6489
6490
6491def return_type(descriptorProvider, rettype, infallible):
6492    result = getRetvalDeclarationForType(rettype, descriptorProvider)
6493    if not infallible:
6494        result = CGWrapper(result, pre="Fallible<", post=">")
6495    return result.define()
6496
6497
6498class CGNativeMember(ClassMethod):
6499    def __init__(self, descriptorProvider, member, name, signature, extendedAttrs,
6500                 breakAfter=True, passJSBitsAsNeeded=True, visibility="public",
6501                 unsafe=False):
6502        """
6503        If passJSBitsAsNeeded is false, we don't automatically pass in a
6504        JSContext* or a JSObject* based on the return and argument types.
6505        """
6506        self.descriptorProvider = descriptorProvider
6507        self.member = member
6508        self.extendedAttrs = extendedAttrs
6509        self.passJSBitsAsNeeded = passJSBitsAsNeeded
6510        breakAfterSelf = "\n" if breakAfter else ""
6511        ClassMethod.__init__(self, name,
6512                             self.getReturnType(signature[0]),
6513                             self.getArgs(signature[0], signature[1]),
6514                             static=member.isStatic(),
6515                             # Mark our getters, which are attrs that
6516                             # have a non-void return type, as const.
6517                             const=(not member.isStatic() and member.isAttr() and
6518                                    not signature[0].isVoid()),
6519                             breakAfterSelf=breakAfterSelf,
6520                             unsafe=unsafe,
6521                             visibility=visibility)
6522
6523    def getReturnType(self, type):
6524        infallible = 'infallible' in self.extendedAttrs
6525        typeDecl = return_type(self.descriptorProvider, type, infallible)
6526        return typeDecl
6527
6528    def getArgs(self, returnType, argList):
6529        return [Argument(arg[1], arg[0]) for arg in method_arguments(self.descriptorProvider,
6530                                                                     returnType,
6531                                                                     argList,
6532                                                                     self.passJSBitsAsNeeded)]
6533
6534
6535class CGCallback(CGClass):
6536    def __init__(self, idlObject, descriptorProvider, baseName, methods):
6537        self.baseName = baseName
6538        self._deps = idlObject.getDeps()
6539        name = idlObject.identifier.name
6540        # For our public methods that needThisHandling we want most of the
6541        # same args and the same return type as what CallbackMember
6542        # generates.  So we want to take advantage of all its
6543        # CGNativeMember infrastructure, but that infrastructure can't deal
6544        # with templates and most especially template arguments.  So just
6545        # cheat and have CallbackMember compute all those things for us.
6546        realMethods = []
6547        for method in methods:
6548            if not method.needThisHandling:
6549                realMethods.append(method)
6550            else:
6551                realMethods.extend(self.getMethodImpls(method))
6552        CGClass.__init__(self, name,
6553                         bases=[ClassBase(baseName)],
6554                         constructors=self.getConstructors(),
6555                         methods=realMethods,
6556                         decorators="#[derive(JSTraceable, PartialEq)]\n#[allow_unrooted_interior]")
6557
6558    def getConstructors(self):
6559        return [ClassConstructor(
6560            [Argument("*mut JSContext", "aCx"), Argument("*mut JSObject", "aCallback")],
6561            bodyInHeader=True,
6562            visibility="pub",
6563            explicit=False,
6564            baseConstructors=[
6565                "%s::new()" % self.baseName
6566            ])]
6567
6568    def getMethodImpls(self, method):
6569        assert method.needThisHandling
6570        args = list(method.args)
6571        # Strip out the JSContext*/JSObject* args
6572        # that got added.
6573        assert args[0].name == "cx" and args[0].argType == "*mut JSContext"
6574        assert args[1].name == "aThisObj" and args[1].argType == "HandleObject"
6575        args = args[2:]
6576        # Record the names of all the arguments, so we can use them when we call
6577        # the private method.
6578        argnames = [arg.name for arg in args]
6579        argnamesWithThis = ["s.get_context()", "thisObjJS.handle()"] + argnames
6580        argnamesWithoutThis = ["s.get_context()", "thisObjJS.handle()"] + argnames
6581        # Now that we've recorded the argnames for our call to our private
6582        # method, insert our optional argument for deciding whether the
6583        # CallSetup should re-throw exceptions on aRv.
6584        args.append(Argument("ExceptionHandling", "aExceptionHandling",
6585                             "ReportExceptions"))
6586
6587        # And now insert our template argument.
6588        argsWithoutThis = list(args)
6589        args.insert(0, Argument("&T", "thisObj"))
6590
6591        # And the self argument
6592        method.args.insert(0, Argument(None, "&self"))
6593        args.insert(0, Argument(None, "&self"))
6594        argsWithoutThis.insert(0, Argument(None, "&self"))
6595
6596        setupCall = "let s = CallSetup::new(self, aExceptionHandling);\n"
6597
6598        bodyWithThis = string.Template(
6599            setupCall +
6600            "rooted!(in(s.get_context()) let mut thisObjJS = ptr::null_mut::<JSObject>());\n"
6601            "wrap_call_this_object(s.get_context(), thisObj, thisObjJS.handle_mut());\n"
6602            "if thisObjJS.is_null() {\n"
6603            "    return Err(JSFailed);\n"
6604            "}\n"
6605            "unsafe { ${methodName}(${callArgs}) }").substitute({
6606                "callArgs": ", ".join(argnamesWithThis),
6607                "methodName": 'self.' + method.name,
6608            })
6609        bodyWithoutThis = string.Template(
6610            setupCall +
6611            "rooted!(in(s.get_context()) let thisObjJS = ptr::null_mut::<JSObject>());\n"
6612            "unsafe { ${methodName}(${callArgs}) }").substitute({
6613                "callArgs": ", ".join(argnamesWithoutThis),
6614                "methodName": 'self.' + method.name,
6615            })
6616        return [ClassMethod(method.name + '_', method.returnType, args,
6617                            bodyInHeader=True,
6618                            templateArgs=["T: DomObject"],
6619                            body=bodyWithThis,
6620                            visibility='pub'),
6621                ClassMethod(method.name + '__', method.returnType, argsWithoutThis,
6622                            bodyInHeader=True,
6623                            body=bodyWithoutThis,
6624                            visibility='pub'),
6625                method]
6626
6627    def deps(self):
6628        return self._deps
6629
6630
6631# We're always fallible
6632def callbackGetterName(attr, descriptor):
6633    return "Get" + MakeNativeName(
6634        descriptor.binaryNameFor(attr.identifier.name))
6635
6636
6637def callbackSetterName(attr, descriptor):
6638    return "Set" + MakeNativeName(
6639        descriptor.binaryNameFor(attr.identifier.name))
6640
6641
6642class CGCallbackFunction(CGCallback):
6643    def __init__(self, callback, descriptorProvider):
6644        CGCallback.__init__(self, callback, descriptorProvider,
6645                            "CallbackFunction",
6646                            methods=[CallCallback(callback, descriptorProvider)])
6647
6648    def getConstructors(self):
6649        return CGCallback.getConstructors(self)
6650
6651
6652class CGCallbackFunctionImpl(CGGeneric):
6653    def __init__(self, callback):
6654        impl = string.Template("""\
6655impl CallbackContainer for ${type} {
6656    unsafe fn new(cx: *mut JSContext, callback: *mut JSObject) -> Rc<${type}> {
6657        ${type}::new(cx, callback)
6658    }
6659
6660    fn callback_holder(&self) -> &CallbackObject {
6661        self.parent.callback_holder()
6662    }
6663}
6664
6665impl ToJSValConvertible for ${type} {
6666    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
6667        self.callback().to_jsval(cx, rval);
6668    }
6669}\
6670""").substitute({"type": callback.identifier.name})
6671        CGGeneric.__init__(self, impl)
6672
6673
6674class CGCallbackInterface(CGCallback):
6675    def __init__(self, descriptor):
6676        iface = descriptor.interface
6677        attrs = [m for m in iface.members if m.isAttr() and not m.isStatic()]
6678        assert not attrs
6679        methods = [m for m in iface.members
6680                   if m.isMethod() and not m.isStatic() and not m.isIdentifierLess()]
6681        methods = [CallbackOperation(m, sig, descriptor) for m in methods
6682                   for sig in m.signatures()]
6683        assert not iface.isJSImplemented() or not iface.ctor()
6684        CGCallback.__init__(self, iface, descriptor, "CallbackInterface", methods)
6685
6686
6687class FakeMember():
6688    def __init__(self):
6689        self.treatNullAs = "Default"
6690
6691    def isStatic(self):
6692        return False
6693
6694    def isAttr(self):
6695        return False
6696
6697    def isMethod(self):
6698        return False
6699
6700    def getExtendedAttribute(self, name):
6701        return None
6702
6703
6704class CallbackMember(CGNativeMember):
6705    def __init__(self, sig, name, descriptorProvider, needThisHandling):
6706        """
6707        needThisHandling is True if we need to be able to accept a specified
6708        thisObj, False otherwise.
6709        """
6710
6711        self.retvalType = sig[0]
6712        self.originalSig = sig
6713        args = sig[1]
6714        self.argCount = len(args)
6715        if self.argCount > 0:
6716            # Check for variadic arguments
6717            lastArg = args[self.argCount - 1]
6718            if lastArg.variadic:
6719                self.argCountStr = (
6720                    "(%d - 1) + %s.len()" % (self.argCount,
6721                                             lastArg.identifier.name))
6722            else:
6723                self.argCountStr = "%d" % self.argCount
6724        self.needThisHandling = needThisHandling
6725        # If needThisHandling, we generate ourselves as private and the caller
6726        # will handle generating public versions that handle the "this" stuff.
6727        visibility = "priv" if needThisHandling else "pub"
6728        # We don't care, for callback codegen, whether our original member was
6729        # a method or attribute or whatnot.  Just always pass FakeMember()
6730        # here.
6731        CGNativeMember.__init__(self, descriptorProvider, FakeMember(),
6732                                name, (self.retvalType, args),
6733                                extendedAttrs={},
6734                                passJSBitsAsNeeded=False,
6735                                unsafe=needThisHandling,
6736                                visibility=visibility)
6737        # We have to do all the generation of our body now, because
6738        # the caller relies on us throwing if we can't manage it.
6739        self.exceptionCode = "return Err(JSFailed);"
6740        self.body = self.getImpl()
6741
6742    def getImpl(self):
6743        replacements = {
6744            "declRval": self.getRvalDecl(),
6745            "returnResult": self.getResultConversion(),
6746            "convertArgs": self.getArgConversions(),
6747            "doCall": self.getCall(),
6748            "setupCall": self.getCallSetup(),
6749        }
6750        if self.argCount > 0:
6751            replacements["argCount"] = self.argCountStr
6752            replacements["argvDecl"] = string.Template(
6753                "rooted_vec!(let mut argv);\n"
6754                "argv.extend((0..${argCount}).map(|_| Heap::default()));\n"
6755            ).substitute(replacements)
6756        else:
6757            # Avoid weird 0-sized arrays
6758            replacements["argvDecl"] = ""
6759
6760        # Newlines and semicolons are in the values
6761        pre = string.Template(
6762            "${setupCall}"
6763            "${declRval}"
6764            "${argvDecl}").substitute(replacements)
6765        body = string.Template(
6766            "${convertArgs}"
6767            "${doCall}"
6768            "${returnResult}").substitute(replacements)
6769        return pre + "\n" + body
6770
6771    def getResultConversion(self):
6772        replacements = {
6773            "val": "rval.handle()",
6774        }
6775
6776        info = getJSToNativeConversionInfo(
6777            self.retvalType,
6778            self.descriptorProvider,
6779            exceptionCode=self.exceptionCode,
6780            isCallbackReturnValue="Callback",
6781            # XXXbz we should try to do better here
6782            sourceDescription="return value")
6783        template = info.template
6784        declType = info.declType
6785
6786        convertType = instantiateJSToNativeConversionTemplate(
6787            template, replacements, declType, "rvalDecl")
6788
6789        if self.retvalType is None or self.retvalType.isVoid():
6790            retval = "()"
6791        elif self.retvalType.isAny():
6792            retval = "rvalDecl.get()"
6793        else:
6794            retval = "rvalDecl"
6795
6796        return "%s\nOk(%s)\n" % (convertType.define(), retval)
6797
6798    def getArgConversions(self):
6799        # Just reget the arglist from self.originalSig, because our superclasses
6800        # just have way to many members they like to clobber, so I can't find a
6801        # safe member name to store it in.
6802        argConversions = [self.getArgConversion(i, arg) for (i, arg)
6803                          in enumerate(self.originalSig[1])]
6804        # Do them back to front, so our argc modifications will work
6805        # correctly, because we examine trailing arguments first.
6806        argConversions.reverse()
6807        argConversions = [CGGeneric(c) for c in argConversions]
6808        if self.argCount > 0:
6809            argConversions.insert(0, self.getArgcDecl())
6810        # And slap them together.
6811        return CGList(argConversions, "\n\n").define() + "\n\n"
6812
6813    def getArgConversion(self, i, arg):
6814        argval = arg.identifier.name
6815
6816        if arg.variadic:
6817            argval = argval + "[idx].get()"
6818            jsvalIndex = "%d + idx" % i
6819        else:
6820            jsvalIndex = "%d" % i
6821            if arg.optional and not arg.defaultValue:
6822                argval += ".clone().unwrap()"
6823
6824        conversion = wrapForType(
6825            "argv_root.handle_mut()", result=argval,
6826            successCode=("{\n" +
6827                         "let arg = &mut argv[%s];\n" +
6828                         "*arg = Heap::default();\n" +
6829                         "arg.set(argv_root.get());\n" +
6830                         "}") % jsvalIndex,
6831            pre="rooted!(in(cx) let mut argv_root = UndefinedValue());")
6832        if arg.variadic:
6833            conversion = string.Template(
6834                "for idx in 0..${arg}.len() {\n" +
6835                CGIndenter(CGGeneric(conversion)).define() + "\n"
6836                "}"
6837            ).substitute({"arg": arg.identifier.name})
6838        elif arg.optional and not arg.defaultValue:
6839            conversion = (
6840                CGIfWrapper("%s.is_some()" % arg.identifier.name,
6841                            CGGeneric(conversion)).define() +
6842                " else if argc == %d {\n"
6843                "    // This is our current trailing argument; reduce argc\n"
6844                "    argc -= 1;\n"
6845                "} else {\n"
6846                "    argv[%d] = Heap::default();\n"
6847                "}" % (i + 1, i))
6848        return conversion
6849
6850    def getArgs(self, returnType, argList):
6851        args = CGNativeMember.getArgs(self, returnType, argList)
6852        if not self.needThisHandling:
6853            # Since we don't need this handling, we're the actual method that
6854            # will be called, so we need an aRethrowExceptions argument.
6855            args.append(Argument("ExceptionHandling", "aExceptionHandling",
6856                                 "ReportExceptions"))
6857            return args
6858        # We want to allow the caller to pass in a "this" object, as
6859        # well as a JSContext.
6860        return [Argument("*mut JSContext", "cx"),
6861                Argument("HandleObject", "aThisObj")] + args
6862
6863    def getCallSetup(self):
6864        if self.needThisHandling:
6865            # It's been done for us already
6866            return ""
6867        return (
6868            "CallSetup s(CallbackPreserveColor(), aRv, aExceptionHandling);\n"
6869            "JSContext* cx = s.get_context();\n"
6870            "if (!cx) {\n"
6871            "    return Err(JSFailed);\n"
6872            "}\n")
6873
6874    def getArgcDecl(self):
6875        if self.argCount <= 1:
6876            return CGGeneric("let argc = %s;" % self.argCountStr)
6877        return CGGeneric("let mut argc = %s;" % self.argCountStr)
6878
6879    @staticmethod
6880    def ensureASCIIName(idlObject):
6881        type = "attribute" if idlObject.isAttr() else "operation"
6882        if re.match("[^\x20-\x7E]", idlObject.identifier.name):
6883            raise SyntaxError('Callback %s name "%s" contains non-ASCII '
6884                              "characters.  We can't handle that.  %s" %
6885                              (type, idlObject.identifier.name,
6886                               idlObject.location))
6887        if re.match('"', idlObject.identifier.name):
6888            raise SyntaxError("Callback %s name '%s' contains "
6889                              "double-quote character.  We can't handle "
6890                              "that.  %s" %
6891                              (type, idlObject.identifier.name,
6892                               idlObject.location))
6893
6894
6895class CallbackMethod(CallbackMember):
6896    def __init__(self, sig, name, descriptorProvider, needThisHandling):
6897        CallbackMember.__init__(self, sig, name, descriptorProvider,
6898                                needThisHandling)
6899
6900    def getRvalDecl(self):
6901        return "rooted!(in(cx) let mut rval = UndefinedValue());\n"
6902
6903    def getCall(self):
6904        replacements = {
6905            "thisObj": self.getThisObj(),
6906            "getCallable": self.getCallableDecl(),
6907            "callGuard": self.getCallGuard(),
6908        }
6909        if self.argCount > 0:
6910            replacements["argv"] = "argv.as_ptr() as *const JSVal"
6911            replacements["argc"] = "argc"
6912        else:
6913            replacements["argv"] = "ptr::null_mut()"
6914            replacements["argc"] = "0"
6915        return string.Template(
6916            "${getCallable}"
6917            "rooted!(in(cx) let rootedThis = ${thisObj});\n"
6918            "let ok = ${callGuard}JS_CallFunctionValue(\n"
6919            "    cx, rootedThis.handle(), callable.handle(),\n"
6920            "    &HandleValueArray {\n"
6921            "        length_: ${argc} as ::libc::size_t,\n"
6922            "        elements_: ${argv}\n"
6923            "    }, rval.handle_mut());\n"
6924            "maybe_resume_unwind();\n"
6925            "if !ok {\n"
6926            "    return Err(JSFailed);\n"
6927            "}\n").substitute(replacements)
6928
6929
6930class CallCallback(CallbackMethod):
6931    def __init__(self, callback, descriptorProvider):
6932        self.callback = callback
6933        CallbackMethod.__init__(self, callback.signatures()[0], "Call",
6934                                descriptorProvider, needThisHandling=True)
6935
6936    def getThisObj(self):
6937        return "aThisObj.get()"
6938
6939    def getCallableDecl(self):
6940        return "rooted!(in(cx) let callable = ObjectValue(self.callback()));\n"
6941
6942    def getCallGuard(self):
6943        if self.callback._treatNonObjectAsNull:
6944            return "!IsCallable(self.callback()) || "
6945        return ""
6946
6947
6948class CallbackOperationBase(CallbackMethod):
6949    """
6950    Common class for implementing various callback operations.
6951    """
6952    def __init__(self, signature, jsName, nativeName, descriptor, singleOperation):
6953        self.singleOperation = singleOperation
6954        self.methodName = jsName
6955        CallbackMethod.__init__(self, signature, nativeName, descriptor, singleOperation)
6956
6957    def getThisObj(self):
6958        if not self.singleOperation:
6959            return "self.callback()"
6960        # This relies on getCallableDecl declaring a boolean
6961        # isCallable in the case when we're a single-operation
6962        # interface.
6963        return "if isCallable { aThisObj.get() } else { self.callback() }"
6964
6965    def getCallableDecl(self):
6966        replacements = {
6967            "methodName": self.methodName
6968        }
6969        getCallableFromProp = string.Template(
6970            'try!(self.parent.get_callable_property(cx, "${methodName}"))'
6971        ).substitute(replacements)
6972        if not self.singleOperation:
6973            return 'rooted!(in(cx) let callable =\n' + getCallableFromProp + ');\n'
6974        return (
6975            'let isCallable = IsCallable(self.callback());\n'
6976            'rooted!(in(cx) let callable =\n' +
6977            CGIndenter(
6978                CGIfElseWrapper('isCallable',
6979                                CGGeneric('ObjectValue(self.callback())'),
6980                                CGGeneric(getCallableFromProp))).define() + ');\n')
6981
6982    def getCallGuard(self):
6983        return ""
6984
6985
6986class CallbackOperation(CallbackOperationBase):
6987    """
6988    Codegen actual WebIDL operations on callback interfaces.
6989    """
6990    def __init__(self, method, signature, descriptor):
6991        self.ensureASCIIName(method)
6992        jsName = method.identifier.name
6993        CallbackOperationBase.__init__(self, signature,
6994                                       jsName,
6995                                       MakeNativeName(descriptor.binaryNameFor(jsName)),
6996                                       descriptor, descriptor.interface.isSingleOperationInterface())
6997
6998
6999class CGIterableMethodGenerator(CGGeneric):
7000    """
7001    Creates methods for iterable interfaces. Unwrapping/wrapping
7002    will be taken care of by the usual method generation machinery in
7003    CGMethodCall/CGPerSignatureCall. Functionality is filled in here instead of
7004    using CGCallGenerator.
7005    """
7006    def __init__(self, descriptor, iterable, methodName):
7007        if methodName == "forEach":
7008            CGGeneric.__init__(self, fill(
7009                """
7010                if !IsCallable(arg0) {
7011                  throw_type_error(cx, "Argument 1 of ${ifaceName}.forEach is not callable.");
7012                  return false;
7013                }
7014                rooted!(in(cx) let arg0 = ObjectValue(arg0));
7015                rooted!(in(cx) let mut call_arg1 = UndefinedValue());
7016                rooted!(in(cx) let mut call_arg2 = UndefinedValue());
7017                let mut call_args = vec![UndefinedValue(), UndefinedValue(), ObjectValue(*_obj)];
7018                rooted!(in(cx) let mut ignoredReturnVal = UndefinedValue());
7019                for i in 0..(*this).get_iterable_length() {
7020                  (*this).get_value_at_index(i).to_jsval(cx, call_arg1.handle_mut());
7021                  (*this).get_key_at_index(i).to_jsval(cx, call_arg2.handle_mut());
7022                  call_args[0] = call_arg1.handle().get();
7023                  call_args[1] = call_arg2.handle().get();
7024                  let call_args = HandleValueArray { length_: 3, elements_: call_args.as_ptr() };
7025                  if !Call(cx, arg1, arg0.handle(), &call_args,
7026                           ignoredReturnVal.handle_mut()) {
7027                    return false;
7028                  }
7029                }
7030
7031                let result = ();
7032                """,
7033                ifaceName=descriptor.interface.identifier.name))
7034            return
7035        CGGeneric.__init__(self, fill(
7036            """
7037            let result = ${iterClass}::new(&*this,
7038                                           IteratorType::${itrMethod},
7039                                           super::${ifaceName}IteratorBinding::Wrap);
7040            """,
7041            iterClass=iteratorNativeType(descriptor, True),
7042            ifaceName=descriptor.interface.identifier.name,
7043            itrMethod=methodName.title()))
7044
7045
7046def camel_to_upper_snake(s):
7047    return "_".join(m.group(0).upper() for m in re.finditer("[A-Z][a-z]*", s))
7048
7049
7050def process_arg(expr, arg):
7051    if arg.type.isGeckoInterface() and not arg.type.unroll().inner.isCallback():
7052        if arg.type.nullable() or arg.type.isSequence() or arg.optional:
7053            expr += ".r()"
7054        else:
7055            expr = "&" + expr
7056    elif isinstance(arg.type, IDLPromiseType):
7057        expr = "&" + expr
7058    return expr
7059
7060
7061class GlobalGenRoots():
7062    """
7063    Roots for global codegen.
7064
7065    To generate code, call the method associated with the target, and then
7066    call the appropriate define/declare method.
7067    """
7068
7069    @staticmethod
7070    def InterfaceObjectMap(config):
7071        mods = [
7072            "dom::bindings::codegen",
7073            "js::jsapi::{HandleObject, JSContext}",
7074            "phf",
7075        ]
7076        imports = CGList([CGGeneric("use %s;" % mod) for mod in mods], "\n")
7077
7078        global_descriptors = config.getDescriptors(isGlobal=True)
7079        flags = [("EMPTY", 0)]
7080        flags.extend(
7081            (camel_to_upper_snake(d.name), 2 ** idx)
7082            for (idx, d) in enumerate(global_descriptors)
7083        )
7084        global_flags = CGWrapper(CGIndenter(CGList([
7085            CGGeneric("const %s = %#x;" % args)
7086            for args in flags
7087        ], "\n")), pre="pub struct Globals: u8 {\n", post="\n}")
7088        globals_ = CGWrapper(CGIndenter(global_flags), pre="bitflags! {\n", post="\n}")
7089
7090        phf = CGGeneric("include!(concat!(env!(\"OUT_DIR\"), \"/InterfaceObjectMapPhf.rs\"));")
7091
7092        return CGList([
7093            CGGeneric(AUTOGENERATED_WARNING_COMMENT),
7094            CGList([imports, globals_, phf], "\n\n")
7095        ])
7096
7097    @staticmethod
7098    def InterfaceObjectMapData(config):
7099        pairs = []
7100        for d in config.getDescriptors(hasInterfaceObject=True, isInline=False):
7101            binding = toBindingNamespace(d.name)
7102            pairs.append((d.name, binding, binding))
7103            for ctor in d.interface.namedConstructors:
7104                pairs.append((ctor.identifier.name, binding, binding))
7105        pairs.sort(key=operator.itemgetter(0))
7106        mappings = [
7107            CGGeneric('"%s": "codegen::Bindings::%s::%s::DefineDOMInterface as unsafe fn(_, _)"' % pair)
7108            for pair in pairs
7109        ]
7110        return CGWrapper(
7111            CGList(mappings, ",\n"),
7112            pre="{\n",
7113            post="\n}\n")
7114
7115    @staticmethod
7116    def PrototypeList(config):
7117        # Prototype ID enum.
7118        interfaces = config.getDescriptors(isCallback=False, isNamespace=False)
7119        protos = [d.name for d in interfaces]
7120        constructors = sorted([MakeNativeName(d.name)
7121                               for d in config.getDescriptors(hasInterfaceObject=True)
7122                               if d.shouldHaveGetConstructorObjectMethod()])
7123
7124        proxies = [d.name for d in config.getDescriptors(proxy=True)]
7125
7126        return CGList([
7127            CGGeneric(AUTOGENERATED_WARNING_COMMENT),
7128            CGGeneric("pub const PROTO_OR_IFACE_LENGTH: usize = %d;\n" % (len(protos) + len(constructors))),
7129            CGGeneric("pub const MAX_PROTO_CHAIN_LENGTH: usize = %d;\n\n" % config.maxProtoChainLength),
7130            CGNonNamespacedEnum('ID', protos, 0, deriving="PartialEq, Copy, Clone", repr="u16"),
7131            CGNonNamespacedEnum('Constructor', constructors, len(protos),
7132                                deriving="PartialEq, Copy, Clone", repr="u16"),
7133            CGWrapper(CGIndenter(CGList([CGGeneric('"' + name + '"') for name in protos],
7134                                        ",\n"),
7135                                 indentLevel=4),
7136                      pre="static INTERFACES: [&'static str; %d] = [\n" % len(protos),
7137                      post="\n];\n\n"),
7138            CGGeneric("pub fn proto_id_to_name(proto_id: u16) -> &'static str {\n"
7139                      "    debug_assert!(proto_id < ID::Last as u16);\n"
7140                      "    INTERFACES[proto_id as usize]\n"
7141                      "}\n\n"),
7142            CGNonNamespacedEnum('Proxies', proxies, 0, deriving="PartialEq, Copy, Clone"),
7143        ])
7144
7145    @staticmethod
7146    def RegisterBindings(config):
7147        # TODO - Generate the methods we want
7148        code = CGList([
7149            CGRegisterProxyHandlers(config),
7150        ], "\n")
7151
7152        return CGImports(code, descriptors=[], callbacks=[], dictionaries=[], enums=[], typedefs=[], imports=[
7153            'dom::bindings::codegen::Bindings',
7154            'dom::bindings::codegen::PrototypeList::Proxies',
7155            'libc',
7156        ], config=config, ignored_warnings=[])
7157
7158    @staticmethod
7159    def InterfaceTypes(config):
7160        descriptors = sorted([MakeNativeName(d.name)
7161                              for d in config.getDescriptors(register=True,
7162                                                             isCallback=False,
7163                                                             isIteratorInterface=False)])
7164        curr = CGList([CGGeneric("pub use dom::%s::%s;\n" % (name.lower(),
7165                                                             MakeNativeName(name)))
7166                       for name in descriptors])
7167        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
7168        return curr
7169
7170    @staticmethod
7171    def Bindings(config):
7172
7173        def leafModule(d):
7174            return getModuleFromObject(d).split('::')[-1]
7175
7176        descriptors = config.getDescriptors(register=True, isIteratorInterface=False)
7177        descriptors = (set(toBindingNamespace(d.name) for d in descriptors) |
7178                       set(leafModule(d) for d in config.callbacks) |
7179                       set(leafModule(d) for d in config.getDictionaries()))
7180        curr = CGList([CGGeneric("pub mod %s;\n" % name) for name in sorted(descriptors)])
7181        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
7182        return curr
7183
7184    @staticmethod
7185    def InheritTypes(config):
7186
7187        descriptors = config.getDescriptors(register=True, isCallback=False)
7188        imports = [CGGeneric("use dom::types::*;\n"),
7189                   CGGeneric("use dom::bindings::conversions::{DerivedFrom, get_dom_class};\n"),
7190                   CGGeneric("use dom::bindings::inheritance::Castable;\n"),
7191                   CGGeneric("use dom::bindings::root::{Dom, DomRoot, LayoutDom};\n"),
7192                   CGGeneric("use dom::bindings::trace::JSTraceable;\n"),
7193                   CGGeneric("use dom::bindings::reflector::DomObject;\n"),
7194                   CGGeneric("use js::jsapi::JSTracer;\n\n"),
7195                   CGGeneric("use std::mem;\n\n")]
7196        allprotos = []
7197        topTypes = []
7198        hierarchy = defaultdict(list)
7199        for descriptor in descriptors:
7200            name = descriptor.name
7201            chain = descriptor.prototypeChain
7202            upcast = descriptor.hasDescendants()
7203            downcast = len(chain) != 1
7204
7205            if upcast and not downcast:
7206                topTypes.append(name)
7207
7208            if not upcast:
7209                # No other interface will implement DeriveFrom<Foo> for this Foo, so avoid
7210                # implementing it for itself.
7211                chain = chain[:-1]
7212
7213            # Implement `DerivedFrom<Bar>` for `Foo`, for all `Bar` that `Foo` inherits from.
7214            if chain:
7215                allprotos.append(CGGeneric("impl Castable for %s {}\n" % name))
7216            for baseName in chain:
7217                allprotos.append(CGGeneric("impl DerivedFrom<%s> for %s {}\n" % (baseName, name)))
7218            if chain:
7219                allprotos.append(CGGeneric("\n"))
7220
7221            if downcast:
7222                hierarchy[descriptor.interface.parent.identifier.name].append(name)
7223
7224        typeIdCode = []
7225        topTypeVariants = [
7226            ("ID used by abstract interfaces.", "pub abstract_: ()"),
7227            ("ID used by interfaces that are not castable.", "pub alone: ()"),
7228        ]
7229        topTypeVariants += [
7230            ("ID used by interfaces that derive from %s." % typeName,
7231             "pub %s: %sTypeId" % (typeName.lower(), typeName))
7232            for typeName in topTypes
7233        ]
7234        topTypeVariantsAsStrings = [CGGeneric("/// %s\n%s," % variant) for variant in topTypeVariants]
7235        typeIdCode.append(CGWrapper(CGIndenter(CGList(topTypeVariantsAsStrings, "\n"), 4),
7236                                    pre="#[derive(Copy)]\npub union TopTypeId {\n",
7237                                    post="\n}\n\n"))
7238
7239        typeIdCode.append(CGGeneric("""\
7240impl Clone for TopTypeId {
7241    fn clone(&self) -> Self { *self }
7242}
7243
7244"""))
7245
7246        def type_id_variant(name):
7247            # If `name` is present in the hierarchy keys', that means some other interfaces
7248            # derive from it and this enum variant should have an argument with its own
7249            # TypeId enum.
7250            return "%s(%sTypeId)" % (name, name) if name in hierarchy else name
7251
7252        for base, derived in hierarchy.iteritems():
7253            variants = []
7254            if config.getDescriptor(base).concrete:
7255                variants.append(CGGeneric(base))
7256            variants += [CGGeneric(type_id_variant(derivedName)) for derivedName in derived]
7257            derives = "Clone, Copy, Debug, PartialEq"
7258            typeIdCode.append(CGWrapper(CGIndenter(CGList(variants, ",\n"), 4),
7259                                        pre="#[derive(%s)]\npub enum %sTypeId {\n" % (derives, base),
7260                                        post="\n}\n\n"))
7261            if base in topTypes:
7262                typeIdCode.append(CGGeneric("""\
7263impl %(base)s {
7264    pub fn type_id(&self) -> &'static %(base)sTypeId {
7265        unsafe {
7266            &get_dom_class(self.reflector().get_jsobject().get())
7267                .unwrap()
7268                .type_id
7269                .%(field)s
7270        }
7271    }
7272}
7273
7274""" % {'base': base, 'field': base.lower()}))
7275
7276        curr = CGList(imports + typeIdCode + allprotos)
7277        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
7278        return curr
7279
7280    @staticmethod
7281    def UnionTypes(config):
7282
7283        curr = UnionTypes(config.getDescriptors(),
7284                          config.getDictionaries(),
7285                          config.getCallbacks(),
7286                          config.typedefs,
7287                          config)
7288
7289        # Add the auto-generated comment.
7290        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
7291
7292        # Done.
7293        return curr
7294
7295    @staticmethod
7296    def SupportedDomApis(config):
7297        descriptors = config.getDescriptors(isExposedConditionally=False)
7298
7299        base_path = os.path.join('dom', 'bindings', 'codegen')
7300        with open(os.path.join(base_path, 'apis.html.template')) as f:
7301            base_template = f.read()
7302        with open(os.path.join(base_path, 'api.html.template')) as f:
7303            api_template = f.read()
7304        with open(os.path.join(base_path, 'property.html.template')) as f:
7305            property_template = f.read()
7306        with open(os.path.join(base_path, 'interface.html.template')) as f:
7307            interface_template = f.read()
7308
7309        apis = []
7310        interfaces = []
7311        for descriptor in descriptors:
7312            props = []
7313            for m in descriptor.interface.members:
7314                if PropertyDefiner.getStringAttr(m, 'Pref') or \
7315                   PropertyDefiner.getStringAttr(m, 'Func') or \
7316                   (m.isMethod() and m.isIdentifierLess()):
7317                    continue
7318                display = m.identifier.name + ('()' if m.isMethod() else '')
7319                props += [property_template.replace('${name}', display)]
7320            name = descriptor.interface.identifier.name
7321            apis += [(api_template.replace('${interface}', name)
7322                                  .replace('${properties}', '\n'.join(props)))]
7323            interfaces += [interface_template.replace('${interface}', name)]
7324
7325        return CGGeneric((base_template.replace('${apis}', '\n'.join(apis))
7326                                       .replace('${interfaces}', '\n'.join(interfaces))))
7327