diff options
Diffstat (limited to 'components/script/dom/bindings/codegen/parser/WebIDL.py')
-rw-r--r-- | components/script/dom/bindings/codegen/parser/WebIDL.py | 148 |
1 files changed, 110 insertions, 38 deletions
diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index 59e32fb7b17..95cf21a65ed 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -1,6 +1,6 @@ # 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 https://mozilla.org/MPL/2.0/. +# file, You can obtain one at http://mozilla.org/MPL/2.0/. """ A WebIDL parser. """ @@ -248,8 +248,14 @@ class IDLScope(IDLObject): return self.QName() def QName(self): - if self._name: - return self._name.QName() + "::" + # 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): @@ -327,6 +333,13 @@ class IDLScope(IDLObject): 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): def __init__(self, location, scope, name): @@ -504,8 +517,10 @@ class IDLExposureMixins(): return 'Window' in self.exposureSet def isExposedOnMainThread(self): - return (self.isExposedInWindow() or - self.isExposedInSystemGlobals()) + return self.isExposedInWindow() + + def isExposedOffMainThread(self): + return len(self.exposureSet - {'Window', 'FakeTestPrimaryGlobal'}) > 0 def isExposedInAnyWorker(self): return len(self.getWorkerExposureSet()) > 0 @@ -516,9 +531,6 @@ class IDLExposureMixins(): def isExposedInAnyWorklet(self): return len(self.getWorkletExposureSet()) > 0 - def isExposedInSystemGlobals(self): - return 'BackstagePass' in self.exposureSet - def isExposedInSomeButNotAllWorkers(self): """ Returns true if the Exposed extended attribute for this interface @@ -597,6 +609,34 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins): return set() +class IDLPartialDictionary(IDLObject): + 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): def __init__(self, location, name, members, nonPartialInterfaceOrNamespace): assert isinstance(name, IDLUnresolvedIdentifier) @@ -1322,7 +1362,6 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): for bindingAlias in member.bindingAliases: checkDuplicateNames(member, bindingAlias, "BindingAlias") - # Conditional exposure makes no sense for interfaces with no # interface object, unless they're navigator properties. # And SecureContext makes sense for interfaces with no interface object, @@ -1704,9 +1743,8 @@ class IDLInterface(IDLInterfaceOrNamespace): self.globalNames = attr.args() else: self.globalNames = [self.identifier.name] - self.parentScope.globalNames.update(self.globalNames) - for globalName in self.globalNames: - self.parentScope.globalNameMapping[globalName].add(self.identifier.name) + self.parentScope.addIfaceGlobalNames(self.identifier.name, + self.globalNames) self._isOnGlobalProtoChain = True elif identifier == "PrimaryGlobal": if not attr.noArguments(): @@ -1719,8 +1757,8 @@ class IDLInterface(IDLInterfaceOrNamespace): self.parentScope.primaryGlobalAttr.location]) self.parentScope.primaryGlobalAttr = attr self.parentScope.primaryGlobalName = self.identifier.name - self.parentScope.globalNames.add(self.identifier.name) - self.parentScope.globalNameMapping[self.identifier.name].add(self.identifier.name) + self.parentScope.addIfaceGlobalNames(self.identifier.name, + [self.identifier.name]) self._isOnGlobalProtoChain = True elif identifier == "SecureContext": if not attr.noArguments(): @@ -1743,7 +1781,6 @@ class IDLInterface(IDLInterfaceOrNamespace): identifier == "LegacyUnenumerableNamedProperties" or identifier == "RunConstructorInCallerCompartment" or identifier == "WantsEventListenerHooks" or - identifier == "NonOrdinaryGetPrototypeOf" or identifier == "Abstract" or identifier == "Inline"): # Known extended attributes that do not take values @@ -1805,7 +1842,7 @@ class IDLNamespace(IDLInterfaceOrNamespace): if not attr.noArguments(): raise WebIDLError("[%s] must not have arguments" % identifier, [attr.location]) - elif identifier == "Pref": + elif identifier == "Pref" or identifier == "Func": # Known extended attributes that take a string value if not attr.hasValue(): raise WebIDLError("[%s] must have a value" % identifier, @@ -1828,6 +1865,7 @@ class IDLDictionary(IDLObjectWithScope): self.parent = parent self._finished = False self.members = list(members) + self._partialDictionaries = [] IDLObjectWithScope.__init__(self, location, parentScope, name) @@ -1864,6 +1902,11 @@ class IDLDictionary(IDLObjectWithScope): # looking at them. self.parent.finish(scope) + # Now go ahead and merge in our partial dictionaries. + for partial in self._partialDictionaries: + partial.finish(scope) + self.members.extend(partial.members) + for member in self.members: member.resolve(self) if not member.isComplete(): @@ -1968,6 +2011,9 @@ class IDLDictionary(IDLObjectWithScope): deps.add(self.parent) return deps + def addPartialDictionary(self, partial): + assert self.identifier.name == partial.identifier.name + self._partialDictionaries.append(partial) class IDLEnum(IDLObjectWithIdentifier): def __init__(self, location, parentScope, name, values): @@ -4333,7 +4379,7 @@ class IDLAttribute(IDLInterfaceMember): [attr.location, self.location]) elif (identifier == "CrossOriginReadable" or identifier == "CrossOriginWritable"): - if not attr.noArguments() and identifier == "CrossOriginReadable": + if not attr.noArguments(): raise WebIDLError("[%s] must take no arguments" % identifier, [attr.location]) if self.isStatic(): @@ -4525,7 +4571,7 @@ class IDLArgument(IDLObjectWithIdentifier): if ((self.type.isDictionary() or self.type.isUnion() and self.type.unroll().hasDictionaryType()) and self.optional and not self.defaultValue and not self.variadic): - # Default optional non-variadic dictionaries to null, + # Default optional non-variadic dictionary arguments to null, # for simplicity, so the codegen doesn't have to special-case this. self.defaultValue = IDLNullValue(self.location) elif self.type.isAny(): @@ -5089,6 +5135,10 @@ class IDLMethod(IDLInterfaceMember, IDLScope): if not attr.noArguments(): raise WebIDLError("[%s] must take no arguments" % identifier, [attr.location]) + if identifier == "CrossOriginCallable" and self.isStatic(): + raise WebIDLError("[CrossOriginCallable] is only allowed on non-static " + "attributes" + [attr.location, self.location]) elif identifier == "Pure": if not attr.noArguments(): raise WebIDLError("[Pure] must take no arguments", @@ -5293,7 +5343,7 @@ class Tokenizer(object): return t def t_IDENTIFIER(self, t): - r'[A-Z_a-z][0-9A-Z_a-z-]*' + r'[_-]?[A-Za-z][0-9A-Z_a-z-]*' t.type = self.keywords.get(t.value, 'IDENTIFIER') return t @@ -5518,9 +5568,10 @@ class Parser(Tokenizer): def handleNonPartialObject(self, location, identifier, constructor, constructorArgs, nonPartialArgs): """ - This handles non-partial objects (interfaces and namespaces) by - checking for an existing partial object, and promoting it to - non-partial as needed. The return value is the non-partial object. + This handles non-partial objects (interfaces, namespaces and + dictionaries) by checking for an existing partial object, and promoting + it to non-partial as needed. The return value is the non-partial + object. constructorArgs are all the args for the constructor except the last one: isKnownNonPartial. @@ -5610,6 +5661,7 @@ class Parser(Tokenizer): """ PartialDefinition : PartialInterface | PartialNamespace + | PartialDictionary """ p[0] = p[1] @@ -5617,17 +5669,17 @@ class Parser(Tokenizer): nonPartialConstructorArgs, partialConstructorArgs): """ - This handles partial objects (interfaces and namespaces) by checking for - an existing non-partial object, and adding ourselves to it as needed. - The return value is our partial object. For now we just use - IDLPartialInterfaceOrNamespace for partial objects. + This handles partial objects (interfaces, namespaces and dictionaries) + by checking for an existing non-partial object, and adding ourselves to + it as needed. The return value is our partial object. We use + IDLPartialInterfaceOrNamespace for partial interfaces or namespaces, + and IDLPartialDictionary for partial dictionaries. nonPartialConstructorArgs are all the args for the non-partial constructor except the last two: members and isKnownNonPartial. - partialConstructorArgs are the arguments for the - IDLPartialInterfaceOrNamespace constructor, except the last one (the - non-partial object). + partialConstructorArgs are the arguments for the partial object + constructor, except the last one (the non-partial object). """ # The name of the class starts with "IDL", so strip that off. # Also, starts with a capital letter after that, so nix that @@ -5652,9 +5704,19 @@ class Parser(Tokenizer): nonPartialObject = nonPartialConstructor( # No members, False for isKnownNonPartial *(nonPartialConstructorArgs + [[], False])) - partialInterface = IDLPartialInterfaceOrNamespace( - *(partialConstructorArgs + [nonPartialObject])) - return partialInterface + + partialObject = None + if isinstance(nonPartialObject, IDLDictionary): + partialObject = IDLPartialDictionary( + *(partialConstructorArgs + [nonPartialObject])) + elif isinstance(nonPartialObject, (IDLInterface, IDLNamespace)): + partialObject = IDLPartialInterfaceOrNamespace( + *(partialConstructorArgs + [nonPartialObject])) + else: + raise WebIDLError("Unknown partial object type %s" % + type(partialObject)) + + return partialObject def p_PartialInterface(self, p): """ @@ -5682,6 +5744,19 @@ class Parser(Tokenizer): [location, self.globalScope(), identifier], [location, identifier, members]) + def p_PartialDictionary(self, p): + """ + PartialDictionary : DICTIONARY IDENTIFIER LBRACE DictionaryMembers RBRACE SEMICOLON + """ + location = self.getLocation(p, 1) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + members = p[4] + + p[0] = self.handlePartialObject( + location, identifier, IDLDictionary, + [location, self.globalScope(), identifier], + [location, identifier, members]) + def p_Inheritance(self, p): """ Inheritance : COLON ScopedName @@ -6894,16 +6969,13 @@ class Parser(Tokenizer): logger.reportGrammarErrors() self._globalScope = IDLScope(BuiltinLocation("<Global Scope>"), None, None) + # To make our test harness work, pretend like we have a primary global already. # Note that we _don't_ set _globalScope.primaryGlobalAttr, # so we'll still be able to detect multiple PrimaryGlobal extended attributes. self._globalScope.primaryGlobalName = "FakeTestPrimaryGlobal" - self._globalScope.globalNames.add("FakeTestPrimaryGlobal") - self._globalScope.globalNameMapping["FakeTestPrimaryGlobal"].add("FakeTestPrimaryGlobal") - # And we add the special-cased "System" global name, which - # doesn't have any corresponding interfaces. - self._globalScope.globalNames.add("System") - self._globalScope.globalNameMapping["System"].add("BackstagePass") + self._globalScope.addIfaceGlobalNames("FakeTestPrimaryGlobal", ["FakeTestPrimaryGlobal"]) + self._installBuiltins(self._globalScope) self._productions = [] |