Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  WebIDL.py   Sprache: Python

 
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

""" A WebIDL parser. """

import copy
import math
import os
import re
import string
import traceback
from collections import OrderedDict, defaultdict
from itertools import chain

from ply import lex, yacc

# Machinery


def parseInt(literal):
    string = literal
    sign = 0
    base = 0

    if string[0] == "-":
        sign = -1
        string = string[1:]
    else:
        sign = 1

    if string[0] == "0" and len(string) > 1:
        if string[1] == "x" or string[1] == "X":
            base = 16
            string = string[2:]
        else:
            base = 8
            string = string[1:]
    else:
        base = 10

    value = int(string, base)
    return value * sign


# This is surprisingly faster than using the enum.IntEnum type (which doesn't
# support 'base' anyway)
def enum(*names, base=None):
    if base is not None:
        names = base.attrs + names

    class CustomEnumType(object):
        attrs = names

        def __setattr__(self, name, value):  # this makes it read-only
            raise NotImplementedError

    for v, k in enumerate(names):
        setattr(CustomEnumType, k, v)

    return CustomEnumType()


class WebIDLError(Exception):
    def __init__(self, message, locations, warning=False):
        self.message = message
        self.locations = [str(loc) for loc in locations]
        self.warning = warning

    def __str__(self):
        return "%s: %s%s%s" % (
            self.warning and "warning" or "error",
            self.message,
            ", " if len(self.locations) != 0 else "",
            "\n".join(self.locations),
        )


class Location(object):
    def __init__(self, lexer, lineno, lexpos, filename):
        self._line = None
        self._lineno = lineno
        self._lexpos = lexpos
        self._lexdata = lexer.lexdata
        self.filename = filename if filename else ""

    def __eq__(self, other):
        return self._lexpos == other._lexpos and self.filename == other.filename

    def resolve(self):
        if self._line:
            return

        startofline = self._lexdata.rfind("\n", 0, self._lexpos) + 1
        endofline = self._lexdata.find("\n", self._lexpos, self._lexpos + 80)
        if endofline != -1:
            self._line = self._lexdata[startofline:endofline]
        else:
            self._line = self._lexdata[startofline:]
        self._colno = self._lexpos - startofline

        # Our line number seems to point to the start of self._lexdata
        self._lineno += self._lexdata.count("\n", 0, startofline)

    def get(self):
        self.resolve()
        return "%s line %s:%s" % (self.filename, self._lineno, self._colno)

    def _pointerline(self):
        return " " * self._colno + "^"

    def __str__(self):
        self.resolve()
        return "%s line %s:%s\n%s\n%s" % (
            self.filename,
            self._lineno,
            self._colno,
            self._line,
            self._pointerline(),
        )


class BuiltinLocation(object):
    __slots__ = "msg""filename"

    def __init__(self, text):
        self.msg = text + "\n"
        self.filename = ""

    def __eq__(self, other):
        return isinstance(other, BuiltinLocation) and self.msg == other.msg

    def resolve(self):
        pass

    def get(self):
        return self.msg

    def __str__(self):
        return self.get()


# Data Model


class IDLObject(object):
    __slots__ = "location""userData""filename"

    def __init__(self, location):
        self.location = location
        self.userData = {}
        self.filename = location and location.filename

    def isInterface(self):
        return False

    def isNamespace(self):
        return False

    def isInterfaceMixin(self):
        return False

    def isEnum(self):
        return False

    def isCallback(self):
        return False

    def isType(self):
        return False

    def isDictionary(self):
        return False

    def isUnion(self):
        return False

    def isTypedef(self):
        return False

    def getUserData(self, key, default):
        return self.userData.get(key, default)

    def setUserData(self, key, value):
        self.userData[key] = value

    def addExtendedAttributes(self, attrs):
        assert False  # Override me!

    def handleExtendedAttribute(self, attr):
        assert False  # Override me!

    def _getDependentObjects(self):
        assert False  # Override me!

    def getDeps(self, visited=None):
        """Return a set of files that this object depends on. If any of
        these files are changed the parser needs to be rerun to regenerate
        a new IDLObject.

        The visited argument is a set of all the objects already visited.
        We must test to see if we are in it, and if so, do nothing.  This
        prevents infinite recursion."""

        # NB: We can't use visited=set() above because the default value is
        # evaluated when the def statement is evaluated, not when the function
        # is executed, so there would be one set for all invocations.
        if visited is None:
            visited = set()

        if self in visited:
            return set()

        visited.add(self)

        deps = set()
        if self.filename != "":
            deps.add(self.filename)

        for d in self._getDependentObjects():
            deps.update(d.getDeps(visited))

        return deps


class IDLScope(IDLObject):
    __slots__ = "parentScope""_name""_dict""globalNames""globalNameMapping"

    def __init__(self, location, parentScope, identifier):
        IDLObject.__init__(self, location)

        self.parentScope = parentScope
        if identifier:
            assert isinstance(identifier, IDLIdentifier)
            self._name = identifier
        else:
            self._name = None

        self._dict = {}
        self.globalNames = set()
        # A mapping from global name to the set of global interfaces
        # that have that global name.
        self.globalNameMapping = defaultdict(set)

    def __str__(self):
        return self.QName()

    def QName(self):
        # It's possible for us to be called before __init__ has been called, for
        # the IDLObjectWithScope case.  In that case, self._name won't be set yet.
        if hasattr(self, "_name"):
            name = self._name
        else:
            name = None
        if name:
            return name.QName() + "::"
        return "::"

    def ensureUnique(self, identifier, object):
        """
        Ensure that there is at most one 'identifier' in scope ('self').
        Note that object can be None.  This occurs if we end up here for an
        interface type we haven't seen yet.
        """
        assert isinstance(identifier, IDLUnresolvedIdentifier)
        assert not object or isinstance(object, IDLObjectWithIdentifier)
        assert not object or object.identifier == identifier

        if identifier.name in self._dict:
            if not object:
                return

            # ensureUnique twice with the same object is not allowed
            assert id(object) != id(self._dict[identifier.name])

            replacement = self.resolveIdentifierConflict(
                self, identifier, self._dict[identifier.name], object
            )
            self._dict[identifier.name] = replacement
            return

        self.addNewIdentifier(identifier, object)

    def addNewIdentifier(self, identifier, object):
        assert object

        self._dict[identifier.name] = object

    def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject):
        if (
            isinstance(originalObject, IDLExternalInterface)
            and isinstance(newObject, IDLExternalInterface)
            and originalObject.identifier.name == newObject.identifier.name
        ):
            return originalObject

        if isinstance(originalObject, IDLExternalInterface) or isinstance(
            newObject, IDLExternalInterface
        ):
            raise WebIDLError(
                "Name collision between "
                "interface declarations for identifier '%s' at '%s' and '%s'"
                % (identifier.name, originalObject.location, newObject.location),
                [],
            )

        if isinstance(originalObject, IDLDictionary) or isinstance(
            newObject, IDLDictionary
        ):
            raise WebIDLError(
                "Name collision between dictionary declarations for "
                "identifier '%s'.\n%s\n%s"
                % (identifier.name, originalObject.location, newObject.location),
                [],
            )

        # We do the merging of overloads here as opposed to in IDLInterface
        # because we need to merge overloads of LegacyFactoryFunctions and we need to
        # detect conflicts in those across interfaces. See also the comment in
        # IDLInterface.addExtendedAttributes for "LegacyFactoryFunction".
        if isinstance(originalObject, IDLMethod) and isinstance(newObject, IDLMethod):
            return originalObject.addOverload(newObject)

        # Default to throwing, derived classes can override.
        raise self.createIdentifierConflictError(identifier, originalObject, newObject)

    def createIdentifierConflictError(self, identifier, originalObject, newObject):
        conflictdesc = "\n\t%s at %s\n\t%s at %s" % (
            originalObject,
            originalObject.location,
            newObject,
            newObject.location,
        )

        return WebIDLError(
            "Multiple unresolvable definitions of identifier '%s' in scope '%s'%s"
            % (identifier.name, str(self), conflictdesc),
            [],
        )

    def _lookupIdentifier(self, identifier):
        return self._dict[identifier.name]

    def lookupIdentifier(self, identifier):
        assert isinstance(identifier, IDLIdentifier)
        assert identifier.scope == self
        return self._lookupIdentifier(identifier)

    def addIfaceGlobalNames(self, interfaceName, globalNames):
        """Record the global names (from |globalNames|) that can be used in
        [Exposed] to expose things in a global named |interfaceName|"""
        self.globalNames.update(globalNames)
        for name in globalNames:
            self.globalNameMapping[name].add(interfaceName)


class IDLIdentifier(IDLObject):
    __slots__ = "name""scope"

    def __init__(self, location, scope, name):
        IDLObject.__init__(self, location)

        self.name = name
        assert isinstance(scope, IDLScope)
        self.scope = scope

    def __str__(self):
        return self.QName()

    def QName(self):
        return self.scope.QName() + self.name

    def __hash__(self):
        return self.QName().__hash__()

    def __eq__(self, other):
        return self.QName() == other.QName()

    def object(self):
        return self.scope.lookupIdentifier(self)


class IDLUnresolvedIdentifier(IDLObject):
    __slots__ = ("name",)

    def __init__(
        self, location, name, allowDoubleUnderscore=False, allowForbidden=False
    ):
        IDLObject.__init__(self, location)

        assert name

        if name == "__noSuchMethod__":
            raise WebIDLError("__noSuchMethod__ is deprecated", [location])

        if name[:2] == "__" and not allowDoubleUnderscore:
            raise WebIDLError("Identifiers beginning with __ are reserved", [location])
        if name[0] == "_" and not allowDoubleUnderscore:
            name = name[1:]
        if name in ["constructor""toString"and not allowForbidden:
            raise WebIDLError(
                "Cannot use reserved identifier '%s'" % (name), [location]
            )

        self.name = name

    def __str__(self):
        return self.QName()

    def QName(self):
        return "::" + self.name

    def resolve(self, scope, object):
        assert isinstance(scope, IDLScope)
        assert not object or isinstance(object, IDLObjectWithIdentifier)
        assert not object or object.identifier == self

        scope.ensureUnique(self, object)

        identifier = IDLIdentifier(self.location, scope, self.name)
        if object:
            object.identifier = identifier
        return identifier

    def finish(self):
        assert False  # Should replace with a resolved identifier first.


class IDLObjectWithIdentifier(IDLObject):
    # no slots, incompatible with multiple inheritance
    def __init__(self, location, parentScope, identifier):
        IDLObject.__init__(self, location)

        assert isinstance(identifier, IDLUnresolvedIdentifier)

        self.identifier = identifier

        if parentScope:
            self.resolve(parentScope)

    def resolve(self, parentScope):
        assert isinstance(parentScope, IDLScope)
        assert isinstance(self.identifier, IDLUnresolvedIdentifier)
        self.identifier.resolve(parentScope, self)


class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope):
    __slots__ = ()

    def __init__(self, location, parentScope, identifier):
        assert isinstance(identifier, IDLUnresolvedIdentifier)

        IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
        IDLScope.__init__(self, location, parentScope, self.identifier)


class IDLIdentifierPlaceholder(IDLObjectWithIdentifier):
    __slots__ = ()

    def __init__(self, location, identifier):
        assert isinstance(identifier, IDLUnresolvedIdentifier)
        IDLObjectWithIdentifier.__init__(self, location, None, identifier)

    def finish(self, scope):
        try:
            scope._lookupIdentifier(self.identifier)
        except Exception:
            raise WebIDLError(
                "Unresolved type '%s'." % self.identifier, [self.location]
            )

        obj = self.identifier.resolve(scope, None)
        return scope.lookupIdentifier(obj)


class IDLExposureMixins:
    # no slots, incompatible with multiple inheritance
    def __init__(self, location):
        # _exposureGlobalNames are the global names listed in our [Exposed]
        # extended attribute.  exposureSet is the exposure set as defined in the
        # Web IDL spec: it contains interface names.
        self._exposureGlobalNames = set()
        self.exposureSet = set()
        self._location = location
        self._globalScope = None

    def finish(self, scope):
        assert scope.parentScope is None
        self._globalScope = scope

        if "*" in self._exposureGlobalNames:
            self._exposureGlobalNames = scope.globalNames
        else:
            # Verify that our [Exposed] value, if any, makes sense.
            for globalName in self._exposureGlobalNames:
                if globalName not in scope.globalNames:
                    raise WebIDLError(
                        "Unknown [Exposed] value %s" % globalName, [self._location]
                    )

        # Verify that we are exposed _somwhere_ if we have some place to be
        # exposed.  We don't want to assert that we're definitely exposed
        # because a lot of our parser tests have small-enough IDL snippets that
        # they don't include any globals, and we don't really want to go through
        # and add global interfaces and [Exposed] annotations to all those
        # tests.
        if len(scope.globalNames) != 0 and len(self._exposureGlobalNames) == 0:
            raise WebIDLError(
                (
                    "'%s' is not exposed anywhere even though we have "
                    "globals to be exposed to"
                )
                % self,
                [self.location],
            )

        globalNameSetToExposureSet(scope, self._exposureGlobalNames, self.exposureSet)

    def isExposedInWindow(self):
        return "Window" in self.exposureSet

    def isExposedInAnyWorker(self):
        return len(self.getWorkerExposureSet()) > 0

    def isExposedInWorkerDebugger(self):
        return len(self.getWorkerDebuggerExposureSet()) > 0

    def isExposedInAnyWorklet(self):
        return len(self.getWorkletExposureSet()) > 0

    def isExposedInSomeButNotAllWorkers(self):
        """
        Returns true if the Exposed extended attribute for this interface
        exposes it in some worker globals but not others.  The return value does
        not depend on whether the interface is exposed in Window or System
        globals.
        """
        if not self.isExposedInAnyWorker():
            return False
        workerScopes = self.parentScope.globalNameMapping["Worker"]
        return len(workerScopes.difference(self.exposureSet)) > 0

    def isExposedInShadowRealms(self):
        return "ShadowRealmGlobalScope" in self.exposureSet

    def getWorkerExposureSet(self):
        workerScopes = self._globalScope.globalNameMapping["Worker"]
        return workerScopes.intersection(self.exposureSet)

    def getWorkletExposureSet(self):
        workletScopes = self._globalScope.globalNameMapping["Worklet"]
        return workletScopes.intersection(self.exposureSet)

    def getWorkerDebuggerExposureSet(self):
        workerDebuggerScopes = self._globalScope.globalNameMapping["WorkerDebugger"]
        return workerDebuggerScopes.intersection(self.exposureSet)


class IDLExternalInterface(IDLObjectWithIdentifier):
    __slots__ = ("parent",)

    def __init__(self, location, parentScope, identifier):
        assert isinstance(identifier, IDLUnresolvedIdentifier)
        assert isinstance(parentScope, IDLScope)
        self.parent = None
        IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
        IDLObjectWithIdentifier.resolve(self, parentScope)

    def finish(self, scope):
        pass

    def validate(self):
        pass

    def isIteratorInterface(self):
        return False

    def isAsyncIteratorInterface(self):
        return False

    def isExternal(self):
        return True

    def isInterface(self):
        return True

    def addExtendedAttributes(self, attrs):
        if len(attrs) != 0:
            raise WebIDLError(
                "There are no extended attributes that are "
                "allowed on external interfaces",
                [attrs[0].location, self.location],
            )

    def resolve(self, parentScope):
        pass

    def getJSImplementation(self):
        return None

    def isJSImplemented(self):
        return False

    def hasProbablyShortLivingWrapper(self):
        return False

    def _getDependentObjects(self):
        return set()


class IDLPartialDictionary(IDLObject):
    __slots__ = "identifier""members""_nonPartialDictionary""_finished"

    def __init__(self, location, name, members, nonPartialDictionary):
        assert isinstance(name, IDLUnresolvedIdentifier)

        IDLObject.__init__(self, location)
        self.identifier = name
        self.members = members
        self._nonPartialDictionary = nonPartialDictionary
        self._finished = False
        nonPartialDictionary.addPartialDictionary(self)

    def addExtendedAttributes(self, attrs):
        pass

    def finish(self, scope):
        if self._finished:
            return
        self._finished = True

        # Need to make sure our non-partial dictionary gets
        # finished so it can report cases when we only have partial
        # dictionaries.
        self._nonPartialDictionary.finish(scope)

    def validate(self):
        pass


class IDLPartialInterfaceOrNamespace(IDLObject):
    __slots__ = (
        "identifier",
        "members",
        "propagatedExtendedAttrs",
        "_haveSecureContextExtendedAttribute",
        "_nonPartialInterfaceOrNamespace",
        "_finished",
    )

    def __init__(self, location, name, members, nonPartialInterfaceOrNamespace):
        assert isinstance(name, IDLUnresolvedIdentifier)

        IDLObject.__init__(self, location)
        self.identifier = name
        self.members = members
        # propagatedExtendedAttrs are the ones that should get
        # propagated to our non-partial interface.
        self.propagatedExtendedAttrs = []
        self._haveSecureContextExtendedAttribute = False
        self._nonPartialInterfaceOrNamespace = nonPartialInterfaceOrNamespace
        self._finished = False
        nonPartialInterfaceOrNamespace.addPartial(self)

    def addExtendedAttributes(self, attrs):
        for attr in attrs:
            identifier = attr.identifier()

            if identifier == "LegacyFactoryFunction":
                self.propagatedExtendedAttrs.append(attr)
            elif identifier == "SecureContext":
                self._haveSecureContextExtendedAttribute = True
                # This gets propagated to all our members.
                for member in self.members:
                    if member.getExtendedAttribute("SecureContext"):
                        typeName = self._nonPartialInterfaceOrNamespace.typeName()
                        raise WebIDLError(
                            "[SecureContext] specified on both a partial %s member "
                            "and on the partial %s itself" % (typeName, typeName),
                            [member.location, attr.location],
                        )
                    member.addExtendedAttributes([attr])
            elif identifier == "Exposed":
                # This just gets propagated to all our members.
                for member in self.members:
                    if len(member._exposureGlobalNames) != 0:
                        typeName = self._nonPartialInterfaceOrNamespace.typeName()
                        raise WebIDLError(
                            "[Exposed] specified on both a partial %s member and "
                            "on the partial %s itself" % (typeName, typeName),
                            [member.location, attr.location],
                        )
                    member.addExtendedAttributes([attr])
            else:
                raise WebIDLError(
                    "Unknown extended attribute %s on partial %s"
                    % (identifier, self._nonPartialInterfaceOrNamespace.typeName()),
                    [attr.location],
                )

    def finish(self, scope):
        if self._finished:
            return
        self._finished = True
        if (
            not self._haveSecureContextExtendedAttribute
            and self._nonPartialInterfaceOrNamespace.getExtendedAttribute(
                "SecureContext"
            )
        ):
            # This gets propagated to all our members.
            for member in self.members:
                if member.getExtendedAttribute("SecureContext"):
                    raise WebIDLError(
                        "[SecureContext] specified on both a "
                        "partial interface member and on the "
                        "non-partial interface",
                        [
                            member.location,
                            self._nonPartialInterfaceOrNamespace.location,
                        ],
                    )
                member.addExtendedAttributes(
                    [
                        IDLExtendedAttribute(
                            self._nonPartialInterfaceOrNamespace.location,
                            ("SecureContext",),
                        )
                    ]
                )
        # Need to make sure our non-partial interface or namespace gets
        # finished so it can report cases when we only have partial
        # interfaces/namespaces.
        self._nonPartialInterfaceOrNamespace.finish(scope)

    def validate(self):
        pass


def convertExposedAttrToGlobalNameSet(exposedAttr, targetSet):
    assert len(targetSet) == 0
    if exposedAttr.hasValue():
        targetSet.add(exposedAttr.value())
    else:
        assert exposedAttr.hasArgs()
        targetSet.update(exposedAttr.args())


def globalNameSetToExposureSet(globalScope, nameSet, exposureSet):
    for name in nameSet:
        exposureSet.update(globalScope.globalNameMapping[name])


# Because WebIDL allows static and regular operations with the same identifier
# we use a special class to be able to store them both in the scope for the
# same identifier.
class IDLOperations:
    __slots__ = "static""regular"

    def __init__(self, static=None, regular=None):
        self.static = static
        self.regular = regular


class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMixins):
    __slots__ = (
        "_finished",
        "members",
        "_partials",
        "_extendedAttrDict",
        "_isKnownNonPartial",
    )

    def __init__(self, location, parentScope, name):
        assert isinstance(parentScope, IDLScope)
        assert isinstance(name, IDLUnresolvedIdentifier)

        self._finished = False
        self.members = []
        self._partials = []
        self._extendedAttrDict = {}
        self._isKnownNonPartial = False

        IDLObjectWithScope.__init__(self, location, parentScope, name)
        IDLExposureMixins.__init__(self, location)

    def finish(self, scope):
        if not self._isKnownNonPartial:
            raise WebIDLError(
                "%s does not have a non-partial declaration" % str(self),
                [self.location],
            )

        IDLExposureMixins.finish(self, scope)

        # Now go ahead and merge in our partials.
        for partial in self._partials:
            partial.finish(scope)
            self.addExtendedAttributes(partial.propagatedExtendedAttrs)
            self.members.extend(partial.members)

    def addNewIdentifier(self, identifier, object):
        if isinstance(object, IDLMethod):
            if object.isStatic():
                object = IDLOperations(static=object)
            else:
                object = IDLOperations(regular=object)

        IDLScope.addNewIdentifier(self, identifier, object)

    def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject):
        assert isinstance(scope, IDLScope)
        assert isinstance(newObject, IDLInterfaceMember)

        # The identifier of a regular operation or static operation must not be
        # the same as the identifier of a constant or attribute.
        if isinstance(newObject, IDLMethod) != isinstance(
            originalObject, IDLOperations
        ):
            if isinstance(originalObject, IDLOperations):
                if originalObject.regular is not None:
                    originalObject = originalObject.regular
                else:
                    assert originalObject.static is not None
                    originalObject = originalObject.static

            raise self.createIdentifierConflictError(
                identifier, originalObject, newObject
            )

        if isinstance(newObject, IDLMethod):
            originalOperations = originalObject
            if newObject.isStatic():
                if originalOperations.static is None:
                    originalOperations.static = newObject
                    return originalOperations

                originalObject = originalOperations.static
            else:
                if originalOperations.regular is None:
                    originalOperations.regular = newObject
                    return originalOperations

                originalObject = originalOperations.regular

            assert isinstance(originalObject, IDLMethod)
        else:
            assert isinstance(originalObject, IDLInterfaceMember)

        retval = IDLScope.resolveIdentifierConflict(
            self, scope, identifier, originalObject, newObject
        )

        if isinstance(newObject, IDLMethod):
            if newObject.isStatic():
                originalOperations.static = retval
            else:
                originalOperations.regular = retval

            retval = originalOperations

        # Might be a ctor, which isn't in self.members
        if newObject in self.members:
            self.members.remove(newObject)
        return retval

    def typeName(self):
        if self.isInterface():
            return "interface"
        if self.isNamespace():
            return "namespace"
        assert self.isInterfaceMixin()
        return "interface mixin"

    def addExtendedAttributes(self, attrs):
        for attr in attrs:
            self.handleExtendedAttribute(attr)
            attrlist = attr.listValue()
            self._extendedAttrDict[attr.identifier()] = (
                attrlist if len(attrlist) else True
            )

    def handleExtendedAttribute(self, attr):
        identifier = attr.identifier()
        if identifier == "Exposed":
            convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
        elif identifier == "SecureContext":
            if not attr.noArguments():
                raise WebIDLError(
                    "[SecureContext] must take no arguments", [attr.location]
                )
            # This gets propagated to all our members.
            for member in self.members:
                if member.getExtendedAttribute("SecureContext"):
                    typeName = self.typeName()
                    raise WebIDLError(
                        "[SecureContext] specified on both an %s member and on "
                        "%s itself" % (typeName, typeName),
                        [member.location, attr.location],
                    )
                member.addExtendedAttributes([attr])
        else:
            raise WebIDLError(
                "Unknown extended attribute %s on %s" % (identifier, self.typeName()),
                [attr.location],
            )

    def getExtendedAttribute(self, name):
        return self._extendedAttrDict.get(name, None)

    def setNonPartial(self, location, members):
        if self._isKnownNonPartial:
            raise WebIDLError(
                "Two non-partial definitions for the same %s" % self.typeName(),
                [location, self.location],
            )
        self._isKnownNonPartial = True
        # Now make it look like we were parsed at this new location, since
        # that's the place where the interface is "really" defined
        self.location = location
        # Put the new members at the beginning
        self.members = members + self.members

    def addPartial(self, partial):
        assert self.identifier.name == partial.identifier.name
        self._partials.append(partial)

    def getPartials(self):
        # Don't let people mutate our guts.
        return list(self._partials)

    def finishMembers(self, scope):
        # Assuming we've merged in our partials, set the _exposureGlobalNames on
        # any members that don't have it set yet.  Note that any partial
        # interfaces that had [Exposed] set have already set up
        # _exposureGlobalNames on all the members coming from them, so this is
        # just implementing the "members default to interface or interface mixin
        # that defined them" and "partial interfaces or interface mixins default
        # to interface or interface mixin they're a partial for" rules from the
        # spec.
        for m in self.members:
            # If m, or the partial m came from, had [Exposed]
            # specified, it already has a nonempty exposure global names set.
            if len(m._exposureGlobalNames) == 0:
                m._exposureGlobalNames.update(self._exposureGlobalNames)
            if m.isAttr() and m.stringifier:
                m.expand(self.members)

        # resolve() will modify self.members, so we need to iterate
        # over a copy of the member list here.
        for member in list(self.members):
            member.resolve(self)

        for member in self.members:
            member.finish(scope)

        # Now that we've finished our members, which has updated their exposure
        # sets, make sure they aren't exposed in places where we are not.
        for member in self.members:
            if not member.exposureSet.issubset(self.exposureSet):
                raise WebIDLError(
                    "Interface or interface mixin member has "
                    "larger exposure set than its container",
                    [member.location, self.location],
                )

    def isExternal(self):
        return False


class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace):
    __slots__ = ("actualExposureGlobalNames",)

    def __init__(self, location, parentScope, name, members, isKnownNonPartial):
        self.actualExposureGlobalNames = set()

        assert isKnownNonPartial or not members
        IDLInterfaceOrInterfaceMixinOrNamespace.__init__(
            self, location, parentScope, name
        )

        if isKnownNonPartial:
            self.setNonPartial(location, members)

    def __str__(self):
        return "Interface mixin '%s'" % self.identifier.name

    def isInterfaceMixin(self):
        return True

    def finish(self, scope):
        if self._finished:
            return
        self._finished = True

        # Expose to the globals of interfaces that includes this mixin if this
        # mixin has no explicit [Exposed] so that its members can be exposed
        # based on the base interface exposure set.
        #
        # Make sure this is done before IDLExposureMixins.finish call, since
        # that converts our set of exposure global names to an actual exposure
        # set.
        hasImplicitExposure = len(self._exposureGlobalNames) == 0
        if hasImplicitExposure:
            self._exposureGlobalNames.update(self.actualExposureGlobalNames)

        IDLInterfaceOrInterfaceMixinOrNamespace.finish(self, scope)

        self.finishMembers(scope)

    def validate(self):
        for member in self.members:
            if member.isAttr():
                if member.inherit:
                    raise WebIDLError(
                        "Interface mixin member cannot include "
                        "an inherited attribute",
                        [member.location, self.location],
                    )
                if member.isStatic():
                    raise WebIDLError(
                        "Interface mixin member cannot include a static member",
                        [member.location, self.location],
                    )

            if member.isMethod():
                if member.isStatic():
                    raise WebIDLError(
                        "Interface mixin member cannot include a static operation",
                        [member.location, self.location],
                    )
                if (
                    member.isGetter()
                    or member.isSetter()
                    or member.isDeleter()
                    or member.isLegacycaller()
                ):
                    raise WebIDLError(
                        "Interface mixin member cannot include a special operation",
                        [member.location, self.location],
                    )

    def _getDependentObjects(self):
        return set(self.members)


class ReflectedHTMLAttributesReturningFrozenArray(object):
    __slots__ = (
        "slotIndex",
        "totalMembersInSlots",
    )

    def __init__(self, slotIndex):
        self.slotIndex = slotIndex
        self.totalMembersInSlots = 0


class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
    __slots__ = (
        "parent",
        "_callback",
        "maplikeOrSetlikeOrIterable",
        "legacyFactoryFunctions",
        "legacyWindowAliases",
        "includedMixins",
        "interfacesBasedOnSelf",
        "_hasChildInterfaces",
        "_isOnGlobalProtoChain",
        "totalMembersInSlots",
        "_ownMembersInSlots",
        "reflectedHTMLAttributesReturningFrozenArray",
        "iterableInterface",
        "asyncIterableInterface",
        "hasCrossOriginMembers",
        "hasDescendantWithCrossOriginMembers",
    )

    def __init__(self, location, parentScope, name, parent, members, isKnownNonPartial):
        assert isKnownNonPartial or not parent
        assert isKnownNonPartial or not members

        self.parent = None
        self._callback = False
        self.maplikeOrSetlikeOrIterable = None
        # legacyFactoryFunctions needs deterministic ordering because bindings code
        # outputs the constructs in the order that legacyFactoryFunctions enumerates
        # them.
        self.legacyFactoryFunctions = []
        self.legacyWindowAliases = []
        self.includedMixins = set()
        # self.interfacesBasedOnSelf is the set of interfaces that inherit from
        # self, including self itself.
        # Used for distinguishability checking.
        self.interfacesBasedOnSelf = {self}
        self._hasChildInterfaces = False
        self._isOnGlobalProtoChain = False

        # Tracking of the number of reserved slots we need for our members and
        # those of ancestor interfaces. Note that reflected HTML attributes that
        # have a FrozenArray<Element> return value also need to be stored in
        # slots. Because we don't want to use a lot of memory to store them when
        # they are not in use we use two levels of storage, the slot points to
        # an array of slots, so these have two indices. These attributes share
        # 1 slot in totalMembersInSlots, and count for 1 slot each in
        # reflectedHTMLAttributesReturningFrozenArray.totalMembersInSlots.
        self.totalMembersInSlots = 0
        # Tracking of the number of own own members we have in slots
        self._ownMembersInSlots = 0
        # Tracking the slot in the binding object for reflected HTML attributes
        # that return a FrozenArray, and the slot in the array stored in that
        # slot in the binding object.
        self.reflectedHTMLAttributesReturningFrozenArray = None
        # If this is an iterator interface, we need to know what iterable
        # interface we're iterating for in order to get its nativeType.
        self.iterableInterface = None
        self.asyncIterableInterface = None
        # True if we have cross-origin members.
        self.hasCrossOriginMembers = False
        # True if some descendant (including ourselves) has cross-origin members
        self.hasDescendantWithCrossOriginMembers = False

        IDLInterfaceOrInterfaceMixinOrNamespace.__init__(
            self, location, parentScope, name
        )

        if isKnownNonPartial:
            self.setNonPartial(location, parent, members)

    def ctor(self):
        identifier = IDLUnresolvedIdentifier(
            self.location, "constructor", allowForbidden=True
        )
        try:
            return self._lookupIdentifier(identifier).static
        except Exception:
            return None

    def isIterable(self):
        return (
            self.maplikeOrSetlikeOrIterable
            and self.maplikeOrSetlikeOrIterable.isIterable()
        )

    def isAsyncIterable(self):
        return (
            self.maplikeOrSetlikeOrIterable
            and self.maplikeOrSetlikeOrIterable.isAsyncIterable()
        )

    def isIteratorInterface(self):
        return self.iterableInterface is not None

    def isAsyncIteratorInterface(self):
        return self.asyncIterableInterface is not None

    def getClassName(self):
        return self.identifier.name

    def finish(self, scope):
        if self._finished:
            return

        self._finished = True

        IDLInterfaceOrInterfaceMixinOrNamespace.finish(self, scope)

        if len(self.legacyWindowAliases) > 0:
            if not self.hasInterfaceObject():
                raise WebIDLError(
                    "Interface %s unexpectedly has [LegacyWindowAlias] "
                    "and [LegacyNoInterfaceObject] together" % self.identifier.name,
                    [self.location],
                )
            if not self.isExposedInWindow():
                raise WebIDLError(
                    "Interface %s has [LegacyWindowAlias] "
                    "but not exposed in Window" % self.identifier.name,
                    [self.location],
                )

        # Generate maplike/setlike interface members. Since generated members
        # need to be treated like regular interface members, do this before
        # things like exposure setting.
        for member in self.members:
            if member.isMaplikeOrSetlikeOrIterable():
                if self.isJSImplemented():
                    raise WebIDLError(
                        "%s declaration used on "
                        "interface that is implemented in JS"
                        % (member.maplikeOrSetlikeOrIterableType),
                        [member.location],
                    )
                if member.valueType.isObservableArray() or (
                    member.hasKeyType() and member.keyType.isObservableArray()
                ):
                    raise WebIDLError(
                        "%s declaration uses ObservableArray as value or key type"
                        % (member.maplikeOrSetlikeOrIterableType),
                        [member.location],
                    )
                # Check that we only have one interface declaration (currently
                # there can only be one maplike/setlike declaration per
                # interface)
                if self.maplikeOrSetlikeOrIterable:
                    raise WebIDLError(
                        "%s declaration used on "
                        "interface that already has %s "
                        "declaration"
                        % (
                            member.maplikeOrSetlikeOrIterableType,
                            self.maplikeOrSetlikeOrIterable.maplikeOrSetlikeOrIterableType,
                        ),
                        [self.maplikeOrSetlikeOrIterable.location, member.location],
                    )
                self.maplikeOrSetlikeOrIterable = member
                # If we've got a maplike or setlike declaration, we'll be building all of
                # our required methods in Codegen. Generate members now.
                self.maplikeOrSetlikeOrIterable.expand(self.members)

        assert not self.parent or isinstance(self.parent, IDLIdentifierPlaceholder)
        parent = self.parent.finish(scope) if self.parent else None
        if parent and isinstance(parent, IDLExternalInterface):
            raise WebIDLError(
                "%s inherits from %s which does not have "
                "a definition" % (self.identifier.name, self.parent.identifier.name),
                [self.location],
            )
        if parent and not isinstance(parent, IDLInterface):
            raise WebIDLError(
                "%s inherits from %s which is not an interface "
                % (self.identifier.name, self.parent.identifier.name),
                [self.location, parent.location],
            )

        self.parent = parent

        assert iter(self.members)

        if self.isNamespace():
            assert not self.parent
            for m in self.members:
                if m.isAttr() or m.isMethod():
                    if m.isStatic():
                        raise WebIDLError(
                            "Don't mark things explicitly static in namespaces",
                            [self.location, m.location],
                        )
                    # Just mark all our methods/attributes as static.  The other
                    # option is to duplicate the relevant InterfaceMembers
                    # production bits but modified to produce static stuff to
                    # start with, but that sounds annoying.
                    m.forceStatic()

        if self.parent:
            self.parent.finish(scope)
            self.parent._hasChildInterfaces = True

            self.totalMembersInSlots = self.parent.totalMembersInSlots

            # Interfaces with [Global] must not have anything inherit from them
            if self.parent.getExtendedAttribute("Global"):
                # Note: This is not a self.parent.isOnGlobalProtoChain() check
                # because ancestors of a [Global] interface can have other
                # descendants.
                raise WebIDLError(
                    "[Global] interface has another interface inheriting from it",
                    [self.location, self.parent.location],
                )

            # Make sure that we're not exposed in places where our parent is not
            if not self.exposureSet.issubset(self.parent.exposureSet):
                raise WebIDLError(
                    "Interface %s is exposed in globals where its "
                    "parent interface %s is not exposed."
                    % (self.identifier.name, self.parent.identifier.name),
                    [self.location, self.parent.location],
                )

            # Callbacks must not inherit from non-callbacks.
            # XXXbz Can non-callbacks inherit from callbacks?  Spec issue pending.
            if self.isCallback():
                if not self.parent.isCallback():
                    raise WebIDLError(
                        "Callback interface %s inheriting from "
                        "non-callback interface %s"
                        % (self.identifier.name, self.parent.identifier.name),
                        [self.location, self.parent.location],
                    )
            elif self.parent.isCallback():
                raise WebIDLError(
                    "Non-callback interface %s inheriting from "
                    "callback interface %s"
                    % (self.identifier.name, self.parent.identifier.name),
                    [self.location, self.parent.location],
                )

            # Interfaces which have interface objects can't inherit
            # from [LegacyNoInterfaceObject] interfaces.
            if self.parent.getExtendedAttribute(
                "LegacyNoInterfaceObject"
            ) and not self.getExtendedAttribute("LegacyNoInterfaceObject"):
                raise WebIDLError(
                    "Interface %s does not have "
                    "[LegacyNoInterfaceObject] but inherits from "
                    "interface %s which does"
                    % (self.identifier.name, self.parent.identifier.name),
                    [self.location, self.parent.location],
                )

            # Interfaces that are not [SecureContext] can't inherit
            # from [SecureContext] interfaces.
            if self.parent.getExtendedAttribute(
                "SecureContext"
            ) and not self.getExtendedAttribute("SecureContext"):
                raise WebIDLError(
                    "Interface %s does not have "
                    "[SecureContext] but inherits from "
                    "interface %s which does"
                    % (self.identifier.name, self.parent.identifier.name),
                    [self.location, self.parent.location],
                )

        for mixin in self.includedMixins:
            mixin.finish(scope)

        cycleInGraph = self.findInterfaceLoopPoint(self)
        if cycleInGraph:
            raise WebIDLError(
                "Interface %s has itself as ancestor" % self.identifier.name,
                [self.location, cycleInGraph.location],
            )

        self.finishMembers(scope)

        ctor = self.ctor()
        if ctor is not None:
            if not self.hasInterfaceObject():
                raise WebIDLError(
                    "Can't have both a constructor and [LegacyNoInterfaceObject]",
                    [self.location, ctor.location],
                )

            if self.globalNames:
                raise WebIDLError(
                    "Can't have both a constructor and [Global]",
                    [self.location, ctor.location],
                )

            assert ctor._exposureGlobalNames == self._exposureGlobalNames
            ctor._exposureGlobalNames.update(self._exposureGlobalNames)
            # Remove the constructor operation from our member list so
            # it doesn't get in the way later.
            self.members.remove(ctor)

        for ctor in self.legacyFactoryFunctions:
            if self.globalNames:
                raise WebIDLError(
                    "Can't have both a legacy factory function and [Global]",
                    [self.location, ctor.location],
                )
            assert len(ctor._exposureGlobalNames) == 0
            ctor._exposureGlobalNames.update(self._exposureGlobalNames)
            ctor.finish(scope)

        # Make a copy of our member list, so things that implement us
        # can get those without all the stuff we implement ourselves
        # admixed.
        self.originalMembers = list(self.members)

        for mixin in sorted(self.includedMixins, key=lambda x: x.identifier.name):
            for mixinMember in mixin.members:
                for member in self.members:
                    if mixinMember.identifier.name == member.identifier.name and (
                        not mixinMember.isMethod()
                        or not member.isMethod()
                        or mixinMember.isStatic() == member.isStatic()
                    ):
                        raise WebIDLError(
                            "Multiple definitions of %s on %s coming from 'includes' statements"
                            % (member.identifier.name, self),
                            [mixinMember.location, member.location],
                        )
            self.members.extend(mixin.members)

        for ancestor in self.getInheritedInterfaces():
            ancestor.interfacesBasedOnSelf.add(self)
            if (
                ancestor.maplikeOrSetlikeOrIterable is not None
                and self.maplikeOrSetlikeOrIterable is not None
            ):
                raise WebIDLError(
                    "Cannot have maplike/setlike on %s that "
                    "inherits %s, which is already "
                    "maplike/setlike"
                    % (self.identifier.name, ancestor.identifier.name),
                    [
                        self.maplikeOrSetlikeOrIterable.location,
                        ancestor.maplikeOrSetlikeOrIterable.location,
                    ],
                )

        # Deal with interfaces marked [LegacyUnforgeable], now that we have our full
        # member list, except unforgeables pulled in from parents.  We want to
        # do this before we set "originatingInterface" on our unforgeable
        # members.
        if self.getExtendedAttribute("LegacyUnforgeable"):
            # Check that the interface already has all the things the
            # spec would otherwise require us to synthesize and is
            # missing the ones we plan to synthesize.
            if not any(m.isMethod() and m.isStringifier() for m in self.members):
                raise WebIDLError(
                    "LegacyUnforgeable interface %s does not have a "
                    "stringifier" % self.identifier.name,
                    [self.location],
                )

            for m in self.members:
                if m.identifier.name == "toJSON":
                    raise WebIDLError(
                        "LegacyUnforgeable interface %s has a "
                        "toJSON so we won't be able to add "
                        "one ourselves" % self.identifier.name,
                        [self.location, m.location],
                    )

                if m.identifier.name == "valueOf" and not m.isStatic():
                    raise WebIDLError(
                        "LegacyUnforgeable interface %s has a valueOf "
                        "member so we won't be able to add one "
                        "ourselves" % self.identifier.name,
                        [self.location, m.location],
                    )

        for member in self.members:
            if (
                (member.isAttr() or member.isMethod())
                and member.isLegacyUnforgeable()
                and not hasattr(member, "originatingInterface")
            ):
                member.originatingInterface = self

        for member in self.members:
            if (
                member.isMethod() and member.getExtendedAttribute("CrossOriginCallable")
            ) or (
                member.isAttr()
                and (
                    member.getExtendedAttribute("CrossOriginReadable")
                    or member.getExtendedAttribute("CrossOriginWritable")
                )
            ):
                self.hasCrossOriginMembers = True
                break

        if self.hasCrossOriginMembers:
            parent = self
            while parent:
                parent.hasDescendantWithCrossOriginMembers = True
                parent = parent.parent

        # Compute slot indices for our members before we pull in unforgeable
        # members from our parent. Also, maplike/setlike declarations get a
        # slot to hold their backing object.
        for member in self.members:
            if (
                member.isAttr()
                and (
                    member.getExtendedAttribute("StoreInSlot")
                    or member.getExtendedAttribute("Cached")
                    or member.type.isObservableArray()
                    or member.getExtendedAttribute(
                        "ReflectedHTMLAttributeReturningFrozenArray"
                    )
                )
            ) or member.isMaplikeOrSetlike():
                if self.isJSImplemented() and not member.isMaplikeOrSetlike():
                    raise WebIDLError(
                        "Interface %s is JS-implemented and we "
                        "don't support [Cached] or [StoreInSlot] or ObservableArray "
                        "on JS-implemented interfaces" % self.identifier.name,
                        [self.location, member.location],
                    )
                if member.slotIndices is None:
                    member.slotIndices = dict()
                if member.getExtendedAttribute(
                    "ReflectedHTMLAttributeReturningFrozenArray"
                ):
                    parent = self.parent
                    while parent:
                        if self.parent.reflectedHTMLAttributesReturningFrozenArray:
                            raise WebIDLError(
                                "Interface %s has at least one attribute marked "
                                "as[ReflectedHTMLAttributeReturningFrozenArray],"
                                "but one of its ancestors also has an attribute "
                                "marked as "
                                "[ReflectedHTMLAttributeReturningFrozenArray]"
                                % self.identifier.name,
                                [self.location, member.location, parent.location],
                            )
                        parent = parent.parent

                    if not self.reflectedHTMLAttributesReturningFrozenArray:
                        self.reflectedHTMLAttributesReturningFrozenArray = (
                            ReflectedHTMLAttributesReturningFrozenArray(
                                self.totalMembersInSlots
                            )
                        )
                        self.totalMembersInSlots += 1
                    member.slotIndices[self.identifier.name] = (
                        self.reflectedHTMLAttributesReturningFrozenArray.slotIndex,
                        self.reflectedHTMLAttributesReturningFrozenArray.totalMembersInSlots,
                    )
                    self.reflectedHTMLAttributesReturningFrozenArray.totalMembersInSlots += (
                        1
                    )
                else:
                    member.slotIndices[self.identifier.name] = self.totalMembersInSlots
                    self.totalMembersInSlots += 1
                if member.getExtendedAttribute("StoreInSlot"):
                    self._ownMembersInSlots += 1

        if self.parent:
            # Make sure we don't shadow any of the [LegacyUnforgeable] attributes on our
            # ancestor interfaces.  We don't have to worry about mixins here, because
            # those have already been imported into the relevant .members lists.  And
            # we don't have to worry about anything other than our parent, because it
            # has already imported its ancestors' unforgeable attributes into its
            # member list.
            for unforgeableMember in (
                member
                for member in self.parent.members
                if (member.isAttr() or member.isMethod())
                and member.isLegacyUnforgeable()
            ):
                shadows = [
                    m
                    for m in self.members
                    if (m.isAttr() or m.isMethod())
                    and not m.isStatic()
                    and m.identifier.name == unforgeableMember.identifier.name
                ]
                if len(shadows) != 0:
                    locs = [unforgeableMember.location] + [s.location for s in shadows]
                    raise WebIDLError(
                        "Interface %s shadows [LegacyUnforgeable] "
                        "members of %s"
                        % (self.identifier.name, ancestor.identifier.name),
                        locs,
                    )
                # And now just stick it in our members, since we won't be
                # inheriting this down the proto chain.  If we really cared we
                # could try to do something where we set up the unforgeable
                # attributes/methods of ancestor interfaces, with their
                # corresponding getters, on our interface, but that gets pretty
                # complicated and seems unnecessary.
                self.members.append(unforgeableMember)

        # At this point, we have all of our members. If the current interface
        # uses maplike/setlike, check for collisions anywhere in the current
        # interface or higher in the inheritance chain.
        if self.maplikeOrSetlikeOrIterable:
            testInterface = self
            isAncestor = False
            while testInterface:
                self.maplikeOrSetlikeOrIterable.checkCollisions(
                    testInterface.members, isAncestor
                )
                isAncestor = True
                testInterface = testInterface.parent

        # Ensure that there's at most one of each {named,indexed}
        # {getter,setter,deleter}, at most one stringifier,
        # and at most one legacycaller.  Note that this last is not
        # quite per spec, but in practice no one overloads
        # legacycallers.  Also note that in practice we disallow
        # indexed deleters, but it simplifies some other code to
        # treat deleter analogously to getter/setter by
        # prefixing it with "named".
        specialMembersSeen = {}
        for member in self.members:
            if not member.isMethod():
                continue

            if member.isGetter():
                memberType = "getters"
            elif member.isSetter():
                memberType = "setters"
            elif member.isDeleter():
                memberType = "deleters"
            elif member.isStringifier():
                memberType = "stringifiers"
            elif member.isLegacycaller():
                memberType = "legacycallers"
            else:
                continue

            if memberType != "stringifiers" and memberType != "legacycallers":
                if member.isNamed():
                    memberType = "named " + memberType
                else:
                    assert member.isIndexed()
                    memberType = "indexed " + memberType

            if memberType in specialMembersSeen:
                raise WebIDLError(
                    "Multiple " + memberType + " on %s" % (self),
                    [
                        self.location,
                        specialMembersSeen[memberType].location,
                        member.location,
                    ],
                )

            specialMembersSeen[memberType] = member

        if self.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
            # Check that we have a named getter.
            if "named getters" not in specialMembersSeen:
                raise WebIDLError(
                    "Interface with [LegacyUnenumerableNamedProperties] does "
                    "not have a named getter",
                    [self.location],
                )
            ancestor = self.parent
            while ancestor:
                if ancestor.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
                    raise WebIDLError(
                        "Interface with [LegacyUnenumerableNamedProperties] "
                        "inherits from another interface with "
                        "[LegacyUnenumerableNamedProperties]",
                        [self.location, ancestor.location],
                    )
                ancestor = ancestor.parent

        if self._isOnGlobalProtoChain:
            # Make sure we have no named setters or deleters
            for memberType in ["setter""deleter"]:
                memberId = "named " + memberType + "s"
                if memberId in specialMembersSeen:
                    raise WebIDLError(
                        "Interface with [Global] has a named %s" % memberType,
                        [self.location, specialMembersSeen[memberId].location],
                    )
            # Make sure we're not [LegacyOverrideBuiltIns]
            if self.getExtendedAttribute("LegacyOverrideBuiltIns"):
                raise WebIDLError(
                    "Interface with [Global] also has [LegacyOverrideBuiltIns]",
                    [self.location],
                )
            # Mark all of our ancestors as being on the global's proto chain too
            parent = self.parent
            while parent:
                # Must not inherit from an interface with [LegacyOverrideBuiltIns]
                if parent.getExtendedAttribute("LegacyOverrideBuiltIns"):
                    raise WebIDLError(
                        "Interface with [Global] inherits from "
                        "interface with [LegacyOverrideBuiltIns]",
                        [self.location, parent.location],
                    )
                parent._isOnGlobalProtoChain = True
                parent = parent.parent

    def validate(self):
        def checkDuplicateNames(member, name, attributeName):
            for m in self.members:
                if m.identifier.name == name:
                    raise WebIDLError(
                        "[%s=%s] has same name as interface member"
                        % (attributeName, name),
                        [member.location, m.location],
                    )
                if m.isMethod() and m != member and name in m.aliases:
                    raise WebIDLError(
                        "conflicting [%s=%s] definitions" % (attributeName, name),
                        [member.location, m.location],
                    )
                if m.isAttr() and m != member and name in m.bindingAliases:
                    raise WebIDLError(
                        "conflicting [%s=%s] definitions" % (attributeName, name),
                        [member.location, m.location],
                    )

        # We also don't support inheriting from unforgeable interfaces.
        if self.getExtendedAttribute("LegacyUnforgeable"and self.hasChildInterfaces():
            locations = [self.location] + list(
                i.location for i in self.interfacesBasedOnSelf if i.parent == self
            )
            raise WebIDLError(
                "%s is an unforgeable ancestor interface" % self.identifier.name,
                locations,
            )

        ctor = self.ctor()
        if ctor is not None:
            ctor.validate()
        for namedCtor in self.legacyFactoryFunctions:
            namedCtor.validate()

        indexedGetter = None
        hasLengthAttribute = False
        for member in self.members:
            member.validate()

            if self.isCallback() and member.getExtendedAttribute("Replaceable"):
                raise WebIDLError(
                    "[Replaceable] used on an attribute on "
                    "interface %s which is a callback interface" % self.identifier.name,
                    [self.location, member.location],
                )

            # Check that PutForwards refers to another attribute and that no
            # cycles exist in forwarded assignments.  Also check for a
            # integer-typed "length" attribute.
            if member.isAttr():
                if member.identifier.name == "length" and member.type.isInteger():
                    hasLengthAttribute = True

                iface = self
                attr = member
                putForwards = attr.getExtendedAttribute("PutForwards")
                if putForwards and self.isCallback():
                    raise WebIDLError(
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=94 H=97 G=95

¤ Dauer der Verarbeitung: 0.24 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge