diff options
author | Patrick Walton <pcwalton@mimiga.net> | 2013-05-28 17:13:40 -0700 |
---|---|---|
committer | Patrick Walton <pcwalton@mimiga.net> | 2013-05-28 17:13:40 -0700 |
commit | bf82bc54f349dd0944c37129af28dec6b43041fe (patch) | |
tree | 685e113347e8afd1965793aefc9743cd9f1f8494 /src/components/script/dom/bindings/codegen/Configuration.py | |
parent | 0ea1a94f8e8a07378d23552a620a45d610db31c7 (diff) | |
download | servo-bf82bc54f349dd0944c37129af28dec6b43041fe.tar.gz servo-bf82bc54f349dd0944c37129af28dec6b43041fe.zip |
Separate the DOM and layout into separate crates.
Diffstat (limited to 'src/components/script/dom/bindings/codegen/Configuration.py')
-rw-r--r-- | src/components/script/dom/bindings/codegen/Configuration.py | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/src/components/script/dom/bindings/codegen/Configuration.py b/src/components/script/dom/bindings/codegen/Configuration.py new file mode 100644 index 00000000000..46e16fdc37c --- /dev/null +++ b/src/components/script/dom/bindings/codegen/Configuration.py @@ -0,0 +1,323 @@ +# 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/. + +autogenerated_comment = "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n" + +class Configuration: + """ + Represents global configuration state based on IDL parse data and + the configuration file. + """ + def __init__(self, filename, parseData): + # Read the configuration file. + glbl = {} + execfile(filename, glbl) + config = glbl['DOMInterfaces'] + + # Build descriptors for all the interfaces we have in the parse data. + # This allows callers to specify a subset of interfaces by filtering + # |parseData|. + self.descriptors = [] + self.interfaces = {} + self.maxProtoChainLength = 0; + for thing in parseData: + if not thing.isInterface(): continue + iface = thing + if iface.identifier.name not in config: continue + self.interfaces[iface.identifier.name] = iface + entry = config[iface.identifier.name] + if not isinstance(entry, list): + assert isinstance(entry, dict) + entry = [entry] + self.descriptors.extend([Descriptor(self, iface, x) for x in entry]) + + # Mark the descriptors for which only a single nativeType implements + # an interface. + for descriptor in self.descriptors: + intefaceName = descriptor.interface.identifier.name + otherDescriptors = [d for d in self.descriptors + if d.interface.identifier.name == intefaceName] + descriptor.uniqueImplementation = len(otherDescriptors) == 1 + + self.enums = [e for e in parseData if e.isEnum()] + self.dictionaries = [d for d in parseData if d.isDictionary()] + + # Keep the descriptor list sorted for determinism. + self.descriptors.sort(lambda x,y: cmp(x.name, y.name)) + + def getInterface(self, ifname): + return self.interfaces[ifname] + def getDescriptors(self, **filters): + """Gets the descriptors that match the given filters.""" + curr = self.descriptors + for key, val in filters.iteritems(): + if key == 'webIDLFile': + getter = lambda x: x.interface.filename() + elif key == 'hasInterfaceObject': + getter = lambda x: (not x.interface.isExternal() and + x.interface.hasInterfaceObject()) + elif key == 'hasInterfacePrototypeObject': + getter = lambda x: (not x.interface.isExternal() and + x.interface.hasInterfacePrototypeObject()) + elif key == 'hasInterfaceOrInterfacePrototypeObject': + getter = lambda x: x.hasInterfaceOrInterfacePrototypeObject() + elif key == 'isCallback': + getter = lambda x: x.interface.isCallback() + elif key == 'isExternal': + getter = lambda x: x.interface.isExternal() + else: + getter = lambda x: getattr(x, key) + curr = filter(lambda x: getter(x) == val, curr) + return curr + def getEnums(self, webIDLFile): + return filter(lambda e: e.filename() == webIDLFile, self.enums) + def getDictionaries(self, webIDLFile): + return filter(lambda d: d.filename() == webIDLFile, self.dictionaries) + def getDescriptor(self, interfaceName, workers): + """ + Gets the appropriate descriptor for the given interface name + and the given workers boolean. + """ + iface = self.getInterface(interfaceName) + descriptors = self.getDescriptors(interface=iface) + + # The only filter we currently have is workers vs non-workers. + matches = filter(lambda x: x.workers is workers, descriptors) + + # After filtering, we should have exactly one result. + if len(matches) is not 1: + raise NoSuchDescriptorError("For " + interfaceName + " found " + + str(len(matches)) + " matches"); + return matches[0] + def getDescriptorProvider(self, workers): + """ + Gets a descriptor provider that can provide descriptors as needed, + for the given workers boolean + """ + return DescriptorProvider(self, workers) + +class NoSuchDescriptorError(TypeError): + def __init__(self, str): + TypeError.__init__(self, str) + +class DescriptorProvider: + """ + A way of getting descriptors for interface names + """ + def __init__(self, config, workers): + self.config = config + self.workers = workers + + def getDescriptor(self, interfaceName): + """ + Gets the appropriate descriptor for the given interface name given the + context of the current descriptor. This selects the appropriate + implementation for cases like workers. + """ + return self.config.getDescriptor(interfaceName, self.workers) + +class Descriptor(DescriptorProvider): + """ + Represents a single descriptor for an interface. See Bindings.conf. + """ + def __init__(self, config, interface, desc): + DescriptorProvider.__init__(self, config, desc.get('workers', False)) + self.interface = interface + + # Read the desc, and fill in the relevant defaults. + ifaceName = self.interface.identifier.name + if self.interface.isExternal() or self.interface.isCallback(): + if self.workers: + nativeTypeDefault = "JSObject" + else: + nativeTypeDefault = "nsIDOM" + ifaceName + else: + if self.workers: + nativeTypeDefault = "workers::" + ifaceName + else: + nativeTypeDefault = ifaceName + + self.nativeType = desc.get('nativeType', nativeTypeDefault) + self.pointerType = desc.get('pointerType', '@mut ') + self.hasInstanceInterface = desc.get('hasInstanceInterface', None) + + # Do something sane for JSObject + if self.nativeType == "JSObject": + headerDefault = "jsapi.h" + else: + headerDefault = self.nativeType + headerDefault = headerDefault.replace("::", "/") + ".h" + self.headerFile = desc.get('headerFile', headerDefault) + + if self.interface.isCallback() or self.interface.isExternal(): + if 'castable' in desc: + raise TypeError("%s is external or callback but has a castable " + "setting" % self.interface.identifier.name) + self.castable = False + else: + self.castable = desc.get('castable', True) + + self.notflattened = desc.get('notflattened', False) + self.register = desc.get('register', True) + + self.hasXPConnectImpls = desc.get('hasXPConnectImpls', False) + + # If we're concrete, we need to crawl our ancestor interfaces and mark + # them as having a concrete descendant. + self.concrete = desc.get('concrete', not self.interface.isExternal()) + if self.concrete: + self.proxy = False + operations = { + 'IndexedGetter': None, + 'IndexedSetter': None, + 'IndexedCreator': None, + 'IndexedDeleter': None, + 'NamedGetter': None, + 'NamedSetter': None, + 'NamedCreator': None, + 'NamedDeleter': None, + 'Stringifier': None + } + iface = self.interface + while iface: + for m in iface.members: + if not m.isMethod(): + continue + + def addOperation(operation, m): + if not operations[operation]: + operations[operation] = m + def addIndexedOrNamedOperation(operation, m): + self.proxy = True + if m.isIndexed(): + operation = 'Indexed' + operation + else: + assert m.isNamed() + operation = 'Named' + operation + addOperation(operation, m) + + if m.isStringifier(): + addOperation('Stringifier', m) + else: + if m.isGetter(): + addIndexedOrNamedOperation('Getter', m) + if m.isSetter(): + addIndexedOrNamedOperation('Setter', m) + if m.isCreator(): + addIndexedOrNamedOperation('Creator', m) + if m.isDeleter(): + addIndexedOrNamedOperation('Deleter', m) + raise TypeError("deleter specified on %s but we " + "don't support deleters yet" % + self.interface.identifier.name) + + iface.setUserData('hasConcreteDescendant', True) + iface = iface.parent + + if self.proxy: + self.operations = operations + iface = self.interface + while iface: + iface.setUserData('hasProxyDescendant', True) + iface = iface.parent + + if self.interface.isExternal() and 'prefable' in desc: + raise TypeError("%s is external but has a prefable setting" % + self.interface.identifier.name) + self.prefable = desc.get('prefable', False) + + self.nativeIsISupports = not self.workers + self.customTrace = desc.get('customTrace', self.workers) + self.customFinalize = desc.get('customFinalize', self.workers) + self.wrapperCache = self.workers or desc.get('wrapperCache', True) + + if not self.wrapperCache and self.prefable: + raise TypeError("Descriptor for %s is prefable but not wrappercached" % + self.interface.identifier.name) + + def make_name(name): + return name + "_workers" if self.workers else name + self.name = make_name(interface.identifier.name) + + # self.extendedAttributes is a dict of dicts, keyed on + # all/getterOnly/setterOnly and then on member name. Values are an + # array of extended attributes. + self.extendedAttributes = { 'all': {}, 'getterOnly': {}, 'setterOnly': {} } + + def addExtendedAttribute(attribute, config): + def add(key, members, attribute): + for member in members: + self.extendedAttributes[key].setdefault(member, []).append(attribute) + + if isinstance(config, dict): + for key in ['all', 'getterOnly', 'setterOnly']: + add(key, config.get(key, []), attribute) + elif isinstance(config, list): + add('all', config, attribute) + else: + assert isinstance(config, str) + if config == '*': + iface = self.interface + while iface: + add('all', map(lambda m: m.name, iface.members), attribute) + iface = iface.parent + else: + add('all', [config], attribute) + + for attribute in ['implicitJSContext', 'resultNotAddRefed']: + addExtendedAttribute(attribute, desc.get(attribute, {})) + + self.binaryNames = desc.get('binaryNames', {}) + + # Build the prototype chain. + self.prototypeChain = [] + parent = interface + while parent: + self.prototypeChain.insert(0, make_name(parent.identifier.name)) + parent = parent.parent + config.maxProtoChainLength = max(config.maxProtoChainLength, + len(self.prototypeChain)) + + def hasInterfaceOrInterfacePrototypeObject(self): + + # Forward-declared interfaces don't need either interface object or + # interface prototype object as they're going to use QI (on main thread) + # or be passed as a JSObject (on worker threads). + if self.interface.isExternal(): + return False + + return self.interface.hasInterfaceObject() or self.interface.hasInterfacePrototypeObject() + + def getExtendedAttributes(self, member, getter=False, setter=False): + def ensureValidThrowsExtendedAttribute(attr): + assert(attr is None or attr is True or len(attr) == 1) + if (attr is not None and attr is not True and + 'Workers' not in attr and 'MainThread' not in attr): + raise TypeError("Unknown value for 'Throws': " + attr[0]) + + def maybeAppendInfallibleToAttrs(attrs, throws): + ensureValidThrowsExtendedAttribute(throws) + if (throws is None or + (throws is not True and + ('Workers' not in throws or not self.workers) and + ('MainThread' not in throws or self.workers))): + attrs.append("infallible") + + name = member.identifier.name + if member.isMethod(): + attrs = self.extendedAttributes['all'].get(name, []) + throws = member.getExtendedAttribute("Throws") + maybeAppendInfallibleToAttrs(attrs, throws) + return attrs + + assert member.isAttr() + assert bool(getter) != bool(setter) + key = 'getterOnly' if getter else 'setterOnly' + attrs = self.extendedAttributes['all'].get(name, []) + self.extendedAttributes[key].get(name, []) + throws = member.getExtendedAttribute("Throws") + if throws is None: + throwsAttr = "GetterThrows" if getter else "SetterThrows" + throws = member.getExtendedAttribute(throwsAttr) + maybeAppendInfallibleToAttrs(attrs, throws) + return attrs |