Bug 1874665 - Distinguish between Callback & Dict in WebIDL. r=peterv
[gecko.git] / dom / bindings / parser / WebIDL.py
blob32c5a155aea1e4de1a9ea1a339e8783921f9db07
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/.
5 """ A WebIDL parser. """
7 import copy
8 import math
9 import os
10 import re
11 import string
12 import traceback
13 from collections import OrderedDict, defaultdict
14 from itertools import chain
16 from ply import lex, yacc
18 # Machinery
21 def parseInt(literal):
22 string = literal
23 sign = 0
24 base = 0
26 if string[0] == "-":
27 sign = -1
28 string = string[1:]
29 else:
30 sign = 1
32 if string[0] == "0" and len(string) > 1:
33 if string[1] == "x" or string[1] == "X":
34 base = 16
35 string = string[2:]
36 else:
37 base = 8
38 string = string[1:]
39 else:
40 base = 10
42 value = int(string, base)
43 return value * sign
46 def enum(*names, **kw):
47 class Foo(object):
48 attrs = OrderedDict()
50 def __init__(self, names):
51 for v, k in enumerate(names):
52 self.attrs[k] = v
54 def __getattr__(self, attr):
55 if attr in self.attrs:
56 return self.attrs[attr]
57 raise AttributeError
59 def __setattr__(self, name, value): # this makes it read-only
60 raise NotImplementedError
62 if "base" not in kw:
63 return Foo(names)
64 return Foo(chain(kw["base"].attrs.keys(), names))
67 class WebIDLError(Exception):
68 def __init__(self, message, locations, warning=False):
69 self.message = message
70 self.locations = [str(loc) for loc in locations]
71 self.warning = warning
73 def __str__(self):
74 return "%s: %s%s%s" % (
75 self.warning and "warning" or "error",
76 self.message,
77 ", " if len(self.locations) != 0 else "",
78 "\n".join(self.locations),
82 class Location(object):
83 def __init__(self, lexer, lineno, lexpos, filename):
84 self._line = None
85 self._lineno = lineno
86 self._lexpos = lexpos
87 self._lexdata = lexer.lexdata
88 self._file = filename if filename else "<unknown>"
90 def __eq__(self, other):
91 return self._lexpos == other._lexpos and self._file == other._file
93 def filename(self):
94 return self._file
96 def resolve(self):
97 if self._line:
98 return
100 startofline = self._lexdata.rfind("\n", 0, self._lexpos) + 1
101 endofline = self._lexdata.find("\n", self._lexpos, self._lexpos + 80)
102 if endofline != -1:
103 self._line = self._lexdata[startofline:endofline]
104 else:
105 self._line = self._lexdata[startofline:]
106 self._colno = self._lexpos - startofline
108 # Our line number seems to point to the start of self._lexdata
109 self._lineno += self._lexdata.count("\n", 0, startofline)
111 def get(self):
112 self.resolve()
113 return "%s line %s:%s" % (self._file, self._lineno, self._colno)
115 def _pointerline(self):
116 return " " * self._colno + "^"
118 def __str__(self):
119 self.resolve()
120 return "%s line %s:%s\n%s\n%s" % (
121 self._file,
122 self._lineno,
123 self._colno,
124 self._line,
125 self._pointerline(),
129 class BuiltinLocation(object):
130 def __init__(self, text):
131 self.msg = text + "\n"
133 def __eq__(self, other):
134 return isinstance(other, BuiltinLocation) and self.msg == other.msg
136 def filename(self):
137 return "<builtin>"
139 def resolve(self):
140 pass
142 def get(self):
143 return self.msg
145 def __str__(self):
146 return self.get()
149 # Data Model
152 class IDLObject(object):
153 def __init__(self, location):
154 self.location = location
155 self.userData = dict()
157 def filename(self):
158 return self.location.filename()
160 def isInterface(self):
161 return False
163 def isNamespace(self):
164 return False
166 def isInterfaceMixin(self):
167 return False
169 def isEnum(self):
170 return False
172 def isCallback(self):
173 return False
175 def isType(self):
176 return False
178 def isDictionary(self):
179 return False
181 def isUnion(self):
182 return False
184 def isTypedef(self):
185 return False
187 def getUserData(self, key, default):
188 return self.userData.get(key, default)
190 def setUserData(self, key, value):
191 self.userData[key] = value
193 def addExtendedAttributes(self, attrs):
194 assert False # Override me!
196 def handleExtendedAttribute(self, attr):
197 assert False # Override me!
199 def _getDependentObjects(self):
200 assert False # Override me!
202 def getDeps(self, visited=None):
203 """Return a set of files that this object depends on. If any of
204 these files are changed the parser needs to be rerun to regenerate
205 a new IDLObject.
207 The visited argument is a set of all the objects already visited.
208 We must test to see if we are in it, and if so, do nothing. This
209 prevents infinite recursion."""
211 # NB: We can't use visited=set() above because the default value is
212 # evaluated when the def statement is evaluated, not when the function
213 # is executed, so there would be one set for all invocations.
214 if visited is None:
215 visited = set()
217 if self in visited:
218 return set()
220 visited.add(self)
222 deps = set()
223 if self.filename() != "<builtin>":
224 deps.add(self.filename())
226 for d in self._getDependentObjects():
227 deps.update(d.getDeps(visited))
229 return deps
232 class IDLScope(IDLObject):
233 def __init__(self, location, parentScope, identifier):
234 IDLObject.__init__(self, location)
236 self.parentScope = parentScope
237 if identifier:
238 assert isinstance(identifier, IDLIdentifier)
239 self._name = identifier
240 else:
241 self._name = None
243 self._dict = {}
244 self.globalNames = set()
245 # A mapping from global name to the set of global interfaces
246 # that have that global name.
247 self.globalNameMapping = defaultdict(set)
249 def __str__(self):
250 return self.QName()
252 def QName(self):
253 # It's possible for us to be called before __init__ has been called, for
254 # the IDLObjectWithScope case. In that case, self._name won't be set yet.
255 if hasattr(self, "_name"):
256 name = self._name
257 else:
258 name = None
259 if name:
260 return name.QName() + "::"
261 return "::"
263 def ensureUnique(self, identifier, object):
265 Ensure that there is at most one 'identifier' in scope ('self').
266 Note that object can be None. This occurs if we end up here for an
267 interface type we haven't seen yet.
269 assert isinstance(identifier, IDLUnresolvedIdentifier)
270 assert not object or isinstance(object, IDLObjectWithIdentifier)
271 assert not object or object.identifier == identifier
273 if identifier.name in self._dict:
274 if not object:
275 return
277 # ensureUnique twice with the same object is not allowed
278 assert id(object) != id(self._dict[identifier.name])
280 replacement = self.resolveIdentifierConflict(
281 self, identifier, self._dict[identifier.name], object
283 self._dict[identifier.name] = replacement
284 return
286 self.addNewIdentifier(identifier, object)
288 def addNewIdentifier(self, identifier, object):
289 assert object
291 self._dict[identifier.name] = object
293 def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject):
294 if (
295 isinstance(originalObject, IDLExternalInterface)
296 and isinstance(newObject, IDLExternalInterface)
297 and originalObject.identifier.name == newObject.identifier.name
299 return originalObject
301 if isinstance(originalObject, IDLExternalInterface) or isinstance(
302 newObject, IDLExternalInterface
304 raise WebIDLError(
305 "Name collision between "
306 "interface declarations for identifier '%s' at '%s' and '%s'"
307 % (identifier.name, originalObject.location, newObject.location),
311 if isinstance(originalObject, IDLDictionary) or isinstance(
312 newObject, IDLDictionary
314 raise WebIDLError(
315 "Name collision between dictionary declarations for "
316 "identifier '%s'.\n%s\n%s"
317 % (identifier.name, originalObject.location, newObject.location),
321 # We do the merging of overloads here as opposed to in IDLInterface
322 # because we need to merge overloads of LegacyFactoryFunctions and we need to
323 # detect conflicts in those across interfaces. See also the comment in
324 # IDLInterface.addExtendedAttributes for "LegacyFactoryFunction".
325 if isinstance(originalObject, IDLMethod) and isinstance(newObject, IDLMethod):
326 return originalObject.addOverload(newObject)
328 # Default to throwing, derived classes can override.
329 raise self.createIdentifierConflictError(identifier, originalObject, newObject)
331 def createIdentifierConflictError(self, identifier, originalObject, newObject):
332 conflictdesc = "\n\t%s at %s\n\t%s at %s" % (
333 originalObject,
334 originalObject.location,
335 newObject,
336 newObject.location,
339 return WebIDLError(
340 "Multiple unresolvable definitions of identifier '%s' in scope '%s'%s"
341 % (identifier.name, str(self), conflictdesc),
345 def _lookupIdentifier(self, identifier):
346 return self._dict[identifier.name]
348 def lookupIdentifier(self, identifier):
349 assert isinstance(identifier, IDLIdentifier)
350 assert identifier.scope == self
351 return self._lookupIdentifier(identifier)
353 def addIfaceGlobalNames(self, interfaceName, globalNames):
354 """Record the global names (from |globalNames|) that can be used in
355 [Exposed] to expose things in a global named |interfaceName|"""
356 self.globalNames.update(globalNames)
357 for name in globalNames:
358 self.globalNameMapping[name].add(interfaceName)
361 class IDLIdentifier(IDLObject):
362 def __init__(self, location, scope, name):
363 IDLObject.__init__(self, location)
365 self.name = name
366 assert isinstance(scope, IDLScope)
367 self.scope = scope
369 def __str__(self):
370 return self.QName()
372 def QName(self):
373 return self.scope.QName() + self.name
375 def __hash__(self):
376 return self.QName().__hash__()
378 def __eq__(self, other):
379 return self.QName() == other.QName()
381 def object(self):
382 return self.scope.lookupIdentifier(self)
385 class IDLUnresolvedIdentifier(IDLObject):
386 def __init__(
387 self, location, name, allowDoubleUnderscore=False, allowForbidden=False
389 IDLObject.__init__(self, location)
391 assert len(name) > 0
393 if name == "__noSuchMethod__":
394 raise WebIDLError("__noSuchMethod__ is deprecated", [location])
396 if name[:2] == "__" and not allowDoubleUnderscore:
397 raise WebIDLError("Identifiers beginning with __ are reserved", [location])
398 if name[0] == "_" and not allowDoubleUnderscore:
399 name = name[1:]
400 if name in ["constructor", "toString"] and not allowForbidden:
401 raise WebIDLError(
402 "Cannot use reserved identifier '%s'" % (name), [location]
405 self.name = name
407 def __str__(self):
408 return self.QName()
410 def QName(self):
411 return "<unresolved scope>::" + self.name
413 def resolve(self, scope, object):
414 assert isinstance(scope, IDLScope)
415 assert not object or isinstance(object, IDLObjectWithIdentifier)
416 assert not object or object.identifier == self
418 scope.ensureUnique(self, object)
420 identifier = IDLIdentifier(self.location, scope, self.name)
421 if object:
422 object.identifier = identifier
423 return identifier
425 def finish(self):
426 assert False # Should replace with a resolved identifier first.
429 class IDLObjectWithIdentifier(IDLObject):
430 def __init__(self, location, parentScope, identifier):
431 IDLObject.__init__(self, location)
433 assert isinstance(identifier, IDLUnresolvedIdentifier)
435 self.identifier = identifier
437 if parentScope:
438 self.resolve(parentScope)
440 def resolve(self, parentScope):
441 assert isinstance(parentScope, IDLScope)
442 assert isinstance(self.identifier, IDLUnresolvedIdentifier)
443 self.identifier.resolve(parentScope, self)
446 class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope):
447 def __init__(self, location, parentScope, identifier):
448 assert isinstance(identifier, IDLUnresolvedIdentifier)
450 IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
451 IDLScope.__init__(self, location, parentScope, self.identifier)
454 class IDLIdentifierPlaceholder(IDLObjectWithIdentifier):
455 def __init__(self, location, identifier):
456 assert isinstance(identifier, IDLUnresolvedIdentifier)
457 IDLObjectWithIdentifier.__init__(self, location, None, identifier)
459 def finish(self, scope):
460 try:
461 scope._lookupIdentifier(self.identifier)
462 except Exception:
463 raise WebIDLError(
464 "Unresolved type '%s'." % self.identifier, [self.location]
467 obj = self.identifier.resolve(scope, None)
468 return scope.lookupIdentifier(obj)
471 class IDLExposureMixins:
472 def __init__(self, location):
473 # _exposureGlobalNames are the global names listed in our [Exposed]
474 # extended attribute. exposureSet is the exposure set as defined in the
475 # Web IDL spec: it contains interface names.
476 self._exposureGlobalNames = set()
477 self.exposureSet = set()
478 self._location = location
479 self._globalScope = None
481 def finish(self, scope):
482 assert scope.parentScope is None
483 self._globalScope = scope
485 if "*" in self._exposureGlobalNames:
486 self._exposureGlobalNames = scope.globalNames
487 else:
488 # Verify that our [Exposed] value, if any, makes sense.
489 for globalName in self._exposureGlobalNames:
490 if globalName not in scope.globalNames:
491 raise WebIDLError(
492 "Unknown [Exposed] value %s" % globalName, [self._location]
495 # Verify that we are exposed _somwhere_ if we have some place to be
496 # exposed. We don't want to assert that we're definitely exposed
497 # because a lot of our parser tests have small-enough IDL snippets that
498 # they don't include any globals, and we don't really want to go through
499 # and add global interfaces and [Exposed] annotations to all those
500 # tests.
501 if len(scope.globalNames) != 0 and len(self._exposureGlobalNames) == 0:
502 raise WebIDLError(
504 "'%s' is not exposed anywhere even though we have "
505 "globals to be exposed to"
507 % self,
508 [self.location],
511 globalNameSetToExposureSet(scope, self._exposureGlobalNames, self.exposureSet)
513 def isExposedInWindow(self):
514 return "Window" in self.exposureSet
516 def isExposedInAnyWorker(self):
517 return len(self.getWorkerExposureSet()) > 0
519 def isExposedInWorkerDebugger(self):
520 return len(self.getWorkerDebuggerExposureSet()) > 0
522 def isExposedInAnyWorklet(self):
523 return len(self.getWorkletExposureSet()) > 0
525 def isExposedInSomeButNotAllWorkers(self):
527 Returns true if the Exposed extended attribute for this interface
528 exposes it in some worker globals but not others. The return value does
529 not depend on whether the interface is exposed in Window or System
530 globals.
532 if not self.isExposedInAnyWorker():
533 return False
534 workerScopes = self.parentScope.globalNameMapping["Worker"]
535 return len(workerScopes.difference(self.exposureSet)) > 0
537 def isExposedInShadowRealms(self):
538 return "ShadowRealmGlobalScope" in self.exposureSet
540 def getWorkerExposureSet(self):
541 workerScopes = self._globalScope.globalNameMapping["Worker"]
542 return workerScopes.intersection(self.exposureSet)
544 def getWorkletExposureSet(self):
545 workletScopes = self._globalScope.globalNameMapping["Worklet"]
546 return workletScopes.intersection(self.exposureSet)
548 def getWorkerDebuggerExposureSet(self):
549 workerDebuggerScopes = self._globalScope.globalNameMapping["WorkerDebugger"]
550 return workerDebuggerScopes.intersection(self.exposureSet)
553 class IDLExternalInterface(IDLObjectWithIdentifier):
554 def __init__(self, location, parentScope, identifier):
555 assert isinstance(identifier, IDLUnresolvedIdentifier)
556 assert isinstance(parentScope, IDLScope)
557 self.parent = None
558 IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
559 IDLObjectWithIdentifier.resolve(self, parentScope)
561 def finish(self, scope):
562 pass
564 def validate(self):
565 pass
567 def isIteratorInterface(self):
568 return False
570 def isAsyncIteratorInterface(self):
571 return False
573 def isExternal(self):
574 return True
576 def isInterface(self):
577 return True
579 def addExtendedAttributes(self, attrs):
580 if len(attrs) != 0:
581 raise WebIDLError(
582 "There are no extended attributes that are "
583 "allowed on external interfaces",
584 [attrs[0].location, self.location],
587 def resolve(self, parentScope):
588 pass
590 def getJSImplementation(self):
591 return None
593 def isJSImplemented(self):
594 return False
596 def hasProbablyShortLivingWrapper(self):
597 return False
599 def _getDependentObjects(self):
600 return set()
603 class IDLPartialDictionary(IDLObject):
604 def __init__(self, location, name, members, nonPartialDictionary):
605 assert isinstance(name, IDLUnresolvedIdentifier)
607 IDLObject.__init__(self, location)
608 self.identifier = name
609 self.members = members
610 self._nonPartialDictionary = nonPartialDictionary
611 self._finished = False
612 nonPartialDictionary.addPartialDictionary(self)
614 def addExtendedAttributes(self, attrs):
615 pass
617 def finish(self, scope):
618 if self._finished:
619 return
620 self._finished = True
622 # Need to make sure our non-partial dictionary gets
623 # finished so it can report cases when we only have partial
624 # dictionaries.
625 self._nonPartialDictionary.finish(scope)
627 def validate(self):
628 pass
631 class IDLPartialInterfaceOrNamespace(IDLObject):
632 def __init__(self, location, name, members, nonPartialInterfaceOrNamespace):
633 assert isinstance(name, IDLUnresolvedIdentifier)
635 IDLObject.__init__(self, location)
636 self.identifier = name
637 self.members = members
638 # propagatedExtendedAttrs are the ones that should get
639 # propagated to our non-partial interface.
640 self.propagatedExtendedAttrs = []
641 self._haveSecureContextExtendedAttribute = False
642 self._nonPartialInterfaceOrNamespace = nonPartialInterfaceOrNamespace
643 self._finished = False
644 nonPartialInterfaceOrNamespace.addPartial(self)
646 def addExtendedAttributes(self, attrs):
647 for attr in attrs:
648 identifier = attr.identifier()
650 if identifier == "LegacyFactoryFunction":
651 self.propagatedExtendedAttrs.append(attr)
652 elif identifier == "SecureContext":
653 self._haveSecureContextExtendedAttribute = True
654 # This gets propagated to all our members.
655 for member in self.members:
656 if member.getExtendedAttribute("SecureContext"):
657 raise WebIDLError(
658 "[SecureContext] specified on both a "
659 "partial interface member and on the "
660 "partial interface itself",
661 [member.location, attr.location],
663 member.addExtendedAttributes([attr])
664 elif identifier == "Exposed":
665 # This just gets propagated to all our members.
666 for member in self.members:
667 if len(member._exposureGlobalNames) != 0:
668 raise WebIDLError(
669 "[Exposed] specified on both a "
670 "partial interface member and on the "
671 "partial interface itself",
672 [member.location, attr.location],
674 member.addExtendedAttributes([attr])
675 else:
676 raise WebIDLError(
677 "Unknown extended attribute %s on partial "
678 "interface" % identifier,
679 [attr.location],
682 def finish(self, scope):
683 if self._finished:
684 return
685 self._finished = True
686 if (
687 not self._haveSecureContextExtendedAttribute
688 and self._nonPartialInterfaceOrNamespace.getExtendedAttribute(
689 "SecureContext"
692 # This gets propagated to all our members.
693 for member in self.members:
694 if member.getExtendedAttribute("SecureContext"):
695 raise WebIDLError(
696 "[SecureContext] specified on both a "
697 "partial interface member and on the "
698 "non-partial interface",
700 member.location,
701 self._nonPartialInterfaceOrNamespace.location,
704 member.addExtendedAttributes(
706 IDLExtendedAttribute(
707 self._nonPartialInterfaceOrNamespace.location,
708 ("SecureContext",),
712 # Need to make sure our non-partial interface or namespace gets
713 # finished so it can report cases when we only have partial
714 # interfaces/namespaces.
715 self._nonPartialInterfaceOrNamespace.finish(scope)
717 def validate(self):
718 pass
721 def convertExposedAttrToGlobalNameSet(exposedAttr, targetSet):
722 assert len(targetSet) == 0
723 if exposedAttr.hasValue():
724 targetSet.add(exposedAttr.value())
725 else:
726 assert exposedAttr.hasArgs()
727 targetSet.update(exposedAttr.args())
730 def globalNameSetToExposureSet(globalScope, nameSet, exposureSet):
731 for name in nameSet:
732 exposureSet.update(globalScope.globalNameMapping[name])
735 # Because WebIDL allows static and regular operations with the same identifier
736 # we use a special class to be able to store them both in the scope for the
737 # same identifier.
738 class IDLOperations:
739 def __init__(self, static=None, regular=None):
740 self.static = static
741 self.regular = regular
744 class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMixins):
745 def __init__(self, location, parentScope, name):
746 assert isinstance(parentScope, IDLScope)
747 assert isinstance(name, IDLUnresolvedIdentifier)
749 self._finished = False
750 self.members = []
751 self._partials = []
752 self._extendedAttrDict = {}
753 self._isKnownNonPartial = False
755 IDLObjectWithScope.__init__(self, location, parentScope, name)
756 IDLExposureMixins.__init__(self, location)
758 def finish(self, scope):
759 if not self._isKnownNonPartial:
760 raise WebIDLError(
761 "%s does not have a non-partial declaration" % str(self),
762 [self.location],
765 IDLExposureMixins.finish(self, scope)
767 # Now go ahead and merge in our partials.
768 for partial in self._partials:
769 partial.finish(scope)
770 self.addExtendedAttributes(partial.propagatedExtendedAttrs)
771 self.members.extend(partial.members)
773 def addNewIdentifier(self, identifier, object):
774 if isinstance(object, IDLMethod):
775 if object.isStatic():
776 object = IDLOperations(static=object)
777 else:
778 object = IDLOperations(regular=object)
780 IDLScope.addNewIdentifier(self, identifier, object)
782 def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject):
783 assert isinstance(scope, IDLScope)
784 assert isinstance(newObject, IDLInterfaceMember)
786 # The identifier of a regular operation or static operation must not be
787 # the same as the identifier of a constant or attribute.
788 if isinstance(newObject, IDLMethod) != isinstance(
789 originalObject, IDLOperations
791 if isinstance(originalObject, IDLOperations):
792 if originalObject.regular is not None:
793 originalObject = originalObject.regular
794 else:
795 assert originalObject.static is not None
796 originalObject = originalObject.static
798 raise self.createIdentifierConflictError(
799 identifier, originalObject, newObject
802 if isinstance(newObject, IDLMethod):
803 originalOperations = originalObject
804 if newObject.isStatic():
805 if originalOperations.static is None:
806 originalOperations.static = newObject
807 return originalOperations
809 originalObject = originalOperations.static
810 else:
811 if originalOperations.regular is None:
812 originalOperations.regular = newObject
813 return originalOperations
815 originalObject = originalOperations.regular
817 assert isinstance(originalObject, IDLMethod)
818 else:
819 assert isinstance(originalObject, IDLInterfaceMember)
821 retval = IDLScope.resolveIdentifierConflict(
822 self, scope, identifier, originalObject, newObject
825 if isinstance(newObject, IDLMethod):
826 if newObject.isStatic():
827 originalOperations.static = retval
828 else:
829 originalOperations.regular = retval
831 retval = originalOperations
833 # Might be a ctor, which isn't in self.members
834 if newObject in self.members:
835 self.members.remove(newObject)
836 return retval
838 def typeName(self):
839 if self.isInterface():
840 return "interface"
841 if self.isNamespace():
842 return "namespace"
843 assert self.isInterfaceMixin()
844 return "interface mixin"
846 def getExtendedAttribute(self, name):
847 return self._extendedAttrDict.get(name, None)
849 def setNonPartial(self, location, members):
850 if self._isKnownNonPartial:
851 raise WebIDLError(
852 "Two non-partial definitions for the " "same %s" % self.typeName(),
853 [location, self.location],
855 self._isKnownNonPartial = True
856 # Now make it look like we were parsed at this new location, since
857 # that's the place where the interface is "really" defined
858 self.location = location
859 # Put the new members at the beginning
860 self.members = members + self.members
862 def addPartial(self, partial):
863 assert self.identifier.name == partial.identifier.name
864 self._partials.append(partial)
866 def getPartials(self):
867 # Don't let people mutate our guts.
868 return list(self._partials)
870 def finishMembers(self, scope):
871 # Assuming we've merged in our partials, set the _exposureGlobalNames on
872 # any members that don't have it set yet. Note that any partial
873 # interfaces that had [Exposed] set have already set up
874 # _exposureGlobalNames on all the members coming from them, so this is
875 # just implementing the "members default to interface or interface mixin
876 # that defined them" and "partial interfaces or interface mixins default
877 # to interface or interface mixin they're a partial for" rules from the
878 # spec.
879 for m in self.members:
880 # If m, or the partial m came from, had [Exposed]
881 # specified, it already has a nonempty exposure global names set.
882 if len(m._exposureGlobalNames) == 0:
883 m._exposureGlobalNames.update(self._exposureGlobalNames)
884 if m.isAttr() and m.stringifier:
885 m.expand(self.members)
887 # resolve() will modify self.members, so we need to iterate
888 # over a copy of the member list here.
889 for member in list(self.members):
890 member.resolve(self)
892 for member in self.members:
893 member.finish(scope)
895 # Now that we've finished our members, which has updated their exposure
896 # sets, make sure they aren't exposed in places where we are not.
897 for member in self.members:
898 if not member.exposureSet.issubset(self.exposureSet):
899 raise WebIDLError(
900 "Interface or interface mixin member has "
901 "larger exposure set than its container",
902 [member.location, self.location],
905 def isExternal(self):
906 return False
909 class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace):
910 def __init__(self, location, parentScope, name, members, isKnownNonPartial):
911 self.actualExposureGlobalNames = set()
913 assert isKnownNonPartial or len(members) == 0
914 IDLInterfaceOrInterfaceMixinOrNamespace.__init__(
915 self, location, parentScope, name
918 if isKnownNonPartial:
919 self.setNonPartial(location, members)
921 def __str__(self):
922 return "Interface mixin '%s'" % self.identifier.name
924 def isInterfaceMixin(self):
925 return True
927 def finish(self, scope):
928 if self._finished:
929 return
930 self._finished = True
932 # Expose to the globals of interfaces that includes this mixin if this
933 # mixin has no explicit [Exposed] so that its members can be exposed
934 # based on the base interface exposure set.
936 # Make sure this is done before IDLExposureMixins.finish call, since
937 # that converts our set of exposure global names to an actual exposure
938 # set.
939 hasImplicitExposure = len(self._exposureGlobalNames) == 0
940 if hasImplicitExposure:
941 self._exposureGlobalNames.update(self.actualExposureGlobalNames)
943 IDLInterfaceOrInterfaceMixinOrNamespace.finish(self, scope)
945 self.finishMembers(scope)
947 def validate(self):
948 for member in self.members:
949 if member.isAttr():
950 if member.inherit:
951 raise WebIDLError(
952 "Interface mixin member cannot include "
953 "an inherited attribute",
954 [member.location, self.location],
956 if member.isStatic():
957 raise WebIDLError(
958 "Interface mixin member cannot include " "a static member",
959 [member.location, self.location],
962 if member.isMethod():
963 if member.isStatic():
964 raise WebIDLError(
965 "Interface mixin member cannot include " "a static operation",
966 [member.location, self.location],
968 if (
969 member.isGetter()
970 or member.isSetter()
971 or member.isDeleter()
972 or member.isLegacycaller()
974 raise WebIDLError(
975 "Interface mixin member cannot include a " "special operation",
976 [member.location, self.location],
979 def addExtendedAttributes(self, attrs):
980 for attr in attrs:
981 identifier = attr.identifier()
983 if identifier == "SecureContext":
984 if not attr.noArguments():
985 raise WebIDLError(
986 "[%s] must take no arguments" % identifier, [attr.location]
988 # This gets propagated to all our members.
989 for member in self.members:
990 if member.getExtendedAttribute("SecureContext"):
991 raise WebIDLError(
992 "[SecureContext] specified on both "
993 "an interface mixin member and on"
994 "the interface mixin itself",
995 [member.location, attr.location],
997 member.addExtendedAttributes([attr])
998 elif identifier == "Exposed":
999 convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
1000 else:
1001 raise WebIDLError(
1002 "Unknown extended attribute %s on interface" % identifier,
1003 [attr.location],
1006 attrlist = attr.listValue()
1007 self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
1009 def _getDependentObjects(self):
1010 return set(self.members)
1013 class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
1014 def __init__(self, location, parentScope, name, parent, members, isKnownNonPartial):
1015 assert isKnownNonPartial or not parent
1016 assert isKnownNonPartial or len(members) == 0
1018 self.parent = None
1019 self._callback = False
1020 self.maplikeOrSetlikeOrIterable = None
1021 # legacyFactoryFunctions needs deterministic ordering because bindings code
1022 # outputs the constructs in the order that legacyFactoryFunctions enumerates
1023 # them.
1024 self.legacyFactoryFunctions = list()
1025 self.legacyWindowAliases = []
1026 self.includedMixins = set()
1027 # self.interfacesBasedOnSelf is the set of interfaces that inherit from
1028 # self, including self itself.
1029 # Used for distinguishability checking.
1030 self.interfacesBasedOnSelf = set([self])
1031 self._hasChildInterfaces = False
1032 self._isOnGlobalProtoChain = False
1034 # Tracking of the number of reserved slots we need for our
1035 # members and those of ancestor interfaces.
1036 self.totalMembersInSlots = 0
1037 # Tracking of the number of own own members we have in slots
1038 self._ownMembersInSlots = 0
1039 # If this is an iterator interface, we need to know what iterable
1040 # interface we're iterating for in order to get its nativeType.
1041 self.iterableInterface = None
1042 self.asyncIterableInterface = None
1043 # True if we have cross-origin members.
1044 self.hasCrossOriginMembers = False
1045 # True if some descendant (including ourselves) has cross-origin members
1046 self.hasDescendantWithCrossOriginMembers = False
1048 IDLInterfaceOrInterfaceMixinOrNamespace.__init__(
1049 self, location, parentScope, name
1052 if isKnownNonPartial:
1053 self.setNonPartial(location, parent, members)
1055 def ctor(self):
1056 identifier = IDLUnresolvedIdentifier(
1057 self.location, "constructor", allowForbidden=True
1059 try:
1060 return self._lookupIdentifier(identifier).static
1061 except Exception:
1062 return None
1064 def isIterable(self):
1065 return (
1066 self.maplikeOrSetlikeOrIterable
1067 and self.maplikeOrSetlikeOrIterable.isIterable()
1070 def isAsyncIterable(self):
1071 return (
1072 self.maplikeOrSetlikeOrIterable
1073 and self.maplikeOrSetlikeOrIterable.isAsyncIterable()
1076 def isIteratorInterface(self):
1077 return self.iterableInterface is not None
1079 def isAsyncIteratorInterface(self):
1080 return self.asyncIterableInterface is not None
1082 def getClassName(self):
1083 return self.identifier.name
1085 def finish(self, scope):
1086 if self._finished:
1087 return
1089 self._finished = True
1091 IDLInterfaceOrInterfaceMixinOrNamespace.finish(self, scope)
1093 if len(self.legacyWindowAliases) > 0:
1094 if not self.hasInterfaceObject():
1095 raise WebIDLError(
1096 "Interface %s unexpectedly has [LegacyWindowAlias] "
1097 "and [LegacyNoInterfaceObject] together" % self.identifier.name,
1098 [self.location],
1100 if not self.isExposedInWindow():
1101 raise WebIDLError(
1102 "Interface %s has [LegacyWindowAlias] "
1103 "but not exposed in Window" % self.identifier.name,
1104 [self.location],
1107 # Generate maplike/setlike interface members. Since generated members
1108 # need to be treated like regular interface members, do this before
1109 # things like exposure setting.
1110 for member in self.members:
1111 if member.isMaplikeOrSetlikeOrIterable():
1112 if self.isJSImplemented():
1113 raise WebIDLError(
1114 "%s declaration used on "
1115 "interface that is implemented in JS"
1116 % (member.maplikeOrSetlikeOrIterableType),
1117 [member.location],
1119 if member.valueType.isObservableArray() or (
1120 member.hasKeyType() and member.keyType.isObservableArray()
1122 raise WebIDLError(
1123 "%s declaration uses ObservableArray as value or key type"
1124 % (member.maplikeOrSetlikeOrIterableType),
1125 [member.location],
1127 # Check that we only have one interface declaration (currently
1128 # there can only be one maplike/setlike declaration per
1129 # interface)
1130 if self.maplikeOrSetlikeOrIterable:
1131 raise WebIDLError(
1132 "%s declaration used on "
1133 "interface that already has %s "
1134 "declaration"
1136 member.maplikeOrSetlikeOrIterableType,
1137 self.maplikeOrSetlikeOrIterable.maplikeOrSetlikeOrIterableType,
1139 [self.maplikeOrSetlikeOrIterable.location, member.location],
1141 self.maplikeOrSetlikeOrIterable = member
1142 # If we've got a maplike or setlike declaration, we'll be building all of
1143 # our required methods in Codegen. Generate members now.
1144 self.maplikeOrSetlikeOrIterable.expand(self.members)
1146 assert not self.parent or isinstance(self.parent, IDLIdentifierPlaceholder)
1147 parent = self.parent.finish(scope) if self.parent else None
1148 if parent and isinstance(parent, IDLExternalInterface):
1149 raise WebIDLError(
1150 "%s inherits from %s which does not have "
1151 "a definition" % (self.identifier.name, self.parent.identifier.name),
1152 [self.location],
1154 if parent and not isinstance(parent, IDLInterface):
1155 raise WebIDLError(
1156 "%s inherits from %s which is not an interface "
1157 % (self.identifier.name, self.parent.identifier.name),
1158 [self.location, parent.location],
1161 self.parent = parent
1163 assert iter(self.members)
1165 if self.isNamespace():
1166 assert not self.parent
1167 for m in self.members:
1168 if m.isAttr() or m.isMethod():
1169 if m.isStatic():
1170 raise WebIDLError(
1171 "Don't mark things explicitly static " "in namespaces",
1172 [self.location, m.location],
1174 # Just mark all our methods/attributes as static. The other
1175 # option is to duplicate the relevant InterfaceMembers
1176 # production bits but modified to produce static stuff to
1177 # start with, but that sounds annoying.
1178 m.forceStatic()
1180 if self.parent:
1181 self.parent.finish(scope)
1182 self.parent._hasChildInterfaces = True
1184 self.totalMembersInSlots = self.parent.totalMembersInSlots
1186 # Interfaces with [Global] must not have anything inherit from them
1187 if self.parent.getExtendedAttribute("Global"):
1188 # Note: This is not a self.parent.isOnGlobalProtoChain() check
1189 # because ancestors of a [Global] interface can have other
1190 # descendants.
1191 raise WebIDLError(
1192 "[Global] interface has another interface " "inheriting from it",
1193 [self.location, self.parent.location],
1196 # Make sure that we're not exposed in places where our parent is not
1197 if not self.exposureSet.issubset(self.parent.exposureSet):
1198 raise WebIDLError(
1199 "Interface %s is exposed in globals where its "
1200 "parent interface %s is not exposed."
1201 % (self.identifier.name, self.parent.identifier.name),
1202 [self.location, self.parent.location],
1205 # Callbacks must not inherit from non-callbacks.
1206 # XXXbz Can non-callbacks inherit from callbacks? Spec issue pending.
1207 if self.isCallback():
1208 if not self.parent.isCallback():
1209 raise WebIDLError(
1210 "Callback interface %s inheriting from "
1211 "non-callback interface %s"
1212 % (self.identifier.name, self.parent.identifier.name),
1213 [self.location, self.parent.location],
1215 elif self.parent.isCallback():
1216 raise WebIDLError(
1217 "Non-callback interface %s inheriting from "
1218 "callback interface %s"
1219 % (self.identifier.name, self.parent.identifier.name),
1220 [self.location, self.parent.location],
1223 # Interfaces which have interface objects can't inherit
1224 # from [LegacyNoInterfaceObject] interfaces.
1225 if self.parent.getExtendedAttribute(
1226 "LegacyNoInterfaceObject"
1227 ) and not self.getExtendedAttribute("LegacyNoInterfaceObject"):
1228 raise WebIDLError(
1229 "Interface %s does not have "
1230 "[LegacyNoInterfaceObject] but inherits from "
1231 "interface %s which does"
1232 % (self.identifier.name, self.parent.identifier.name),
1233 [self.location, self.parent.location],
1236 # Interfaces that are not [SecureContext] can't inherit
1237 # from [SecureContext] interfaces.
1238 if self.parent.getExtendedAttribute(
1239 "SecureContext"
1240 ) and not self.getExtendedAttribute("SecureContext"):
1241 raise WebIDLError(
1242 "Interface %s does not have "
1243 "[SecureContext] but inherits from "
1244 "interface %s which does"
1245 % (self.identifier.name, self.parent.identifier.name),
1246 [self.location, self.parent.location],
1249 for mixin in self.includedMixins:
1250 mixin.finish(scope)
1252 cycleInGraph = self.findInterfaceLoopPoint(self)
1253 if cycleInGraph:
1254 raise WebIDLError(
1255 "Interface %s has itself as ancestor" % self.identifier.name,
1256 [self.location, cycleInGraph.location],
1259 self.finishMembers(scope)
1261 ctor = self.ctor()
1262 if ctor is not None:
1263 if not self.hasInterfaceObject():
1264 raise WebIDLError(
1265 "Can't have both a constructor and [LegacyNoInterfaceObject]",
1266 [self.location, ctor.location],
1269 if self.globalNames:
1270 raise WebIDLError(
1271 "Can't have both a constructor and [Global]",
1272 [self.location, ctor.location],
1275 assert ctor._exposureGlobalNames == self._exposureGlobalNames
1276 ctor._exposureGlobalNames.update(self._exposureGlobalNames)
1277 # Remove the constructor operation from our member list so
1278 # it doesn't get in the way later.
1279 self.members.remove(ctor)
1281 for ctor in self.legacyFactoryFunctions:
1282 if self.globalNames:
1283 raise WebIDLError(
1284 "Can't have both a legacy factory function and [Global]",
1285 [self.location, ctor.location],
1287 assert len(ctor._exposureGlobalNames) == 0
1288 ctor._exposureGlobalNames.update(self._exposureGlobalNames)
1289 ctor.finish(scope)
1291 # Make a copy of our member list, so things that implement us
1292 # can get those without all the stuff we implement ourselves
1293 # admixed.
1294 self.originalMembers = list(self.members)
1296 for mixin in sorted(self.includedMixins, key=lambda x: x.identifier.name):
1297 for mixinMember in mixin.members:
1298 for member in self.members:
1299 if mixinMember.identifier.name == member.identifier.name and (
1300 not mixinMember.isMethod()
1301 or not member.isMethod()
1302 or mixinMember.isStatic() == member.isStatic()
1304 raise WebIDLError(
1305 "Multiple definitions of %s on %s coming from 'includes' statements"
1306 % (member.identifier.name, self),
1307 [mixinMember.location, member.location],
1309 self.members.extend(mixin.members)
1311 for ancestor in self.getInheritedInterfaces():
1312 ancestor.interfacesBasedOnSelf.add(self)
1313 if (
1314 ancestor.maplikeOrSetlikeOrIterable is not None
1315 and self.maplikeOrSetlikeOrIterable is not None
1317 raise WebIDLError(
1318 "Cannot have maplike/setlike on %s that "
1319 "inherits %s, which is already "
1320 "maplike/setlike"
1321 % (self.identifier.name, ancestor.identifier.name),
1323 self.maplikeOrSetlikeOrIterable.location,
1324 ancestor.maplikeOrSetlikeOrIterable.location,
1328 # Deal with interfaces marked [LegacyUnforgeable], now that we have our full
1329 # member list, except unforgeables pulled in from parents. We want to
1330 # do this before we set "originatingInterface" on our unforgeable
1331 # members.
1332 if self.getExtendedAttribute("LegacyUnforgeable"):
1333 # Check that the interface already has all the things the
1334 # spec would otherwise require us to synthesize and is
1335 # missing the ones we plan to synthesize.
1336 if not any(m.isMethod() and m.isStringifier() for m in self.members):
1337 raise WebIDLError(
1338 "LegacyUnforgeable interface %s does not have a "
1339 "stringifier" % self.identifier.name,
1340 [self.location],
1343 for m in self.members:
1344 if m.identifier.name == "toJSON":
1345 raise WebIDLError(
1346 "LegacyUnforgeable interface %s has a "
1347 "toJSON so we won't be able to add "
1348 "one ourselves" % self.identifier.name,
1349 [self.location, m.location],
1352 if m.identifier.name == "valueOf" and not m.isStatic():
1353 raise WebIDLError(
1354 "LegacyUnforgeable interface %s has a valueOf "
1355 "member so we won't be able to add one "
1356 "ourselves" % self.identifier.name,
1357 [self.location, m.location],
1360 for member in self.members:
1361 if (
1362 (member.isAttr() or member.isMethod())
1363 and member.isLegacyUnforgeable()
1364 and not hasattr(member, "originatingInterface")
1366 member.originatingInterface = self
1368 for member in self.members:
1369 if (
1370 member.isMethod() and member.getExtendedAttribute("CrossOriginCallable")
1371 ) or (
1372 member.isAttr()
1373 and (
1374 member.getExtendedAttribute("CrossOriginReadable")
1375 or member.getExtendedAttribute("CrossOriginWritable")
1378 self.hasCrossOriginMembers = True
1379 break
1381 if self.hasCrossOriginMembers:
1382 parent = self
1383 while parent:
1384 parent.hasDescendantWithCrossOriginMembers = True
1385 parent = parent.parent
1387 # Compute slot indices for our members before we pull in unforgeable
1388 # members from our parent. Also, maplike/setlike declarations get a
1389 # slot to hold their backing object.
1390 for member in self.members:
1391 if (
1392 member.isAttr()
1393 and (
1394 member.getExtendedAttribute("StoreInSlot")
1395 or member.getExtendedAttribute("Cached")
1396 or member.type.isObservableArray()
1398 ) or member.isMaplikeOrSetlike():
1399 if self.isJSImplemented() and not member.isMaplikeOrSetlike():
1400 raise WebIDLError(
1401 "Interface %s is JS-implemented and we "
1402 "don't support [Cached] or [StoreInSlot] or ObservableArray "
1403 "on JS-implemented interfaces" % self.identifier.name,
1404 [self.location, member.location],
1406 if member.slotIndices is None:
1407 member.slotIndices = dict()
1408 member.slotIndices[self.identifier.name] = self.totalMembersInSlots
1409 self.totalMembersInSlots += 1
1410 if member.getExtendedAttribute("StoreInSlot"):
1411 self._ownMembersInSlots += 1
1413 if self.parent:
1414 # Make sure we don't shadow any of the [LegacyUnforgeable] attributes on our
1415 # ancestor interfaces. We don't have to worry about mixins here, because
1416 # those have already been imported into the relevant .members lists. And
1417 # we don't have to worry about anything other than our parent, because it
1418 # has already imported its ancestors' unforgeable attributes into its
1419 # member list.
1420 for unforgeableMember in (
1421 member
1422 for member in self.parent.members
1423 if (member.isAttr() or member.isMethod())
1424 and member.isLegacyUnforgeable()
1426 shadows = [
1428 for m in self.members
1429 if (m.isAttr() or m.isMethod())
1430 and not m.isStatic()
1431 and m.identifier.name == unforgeableMember.identifier.name
1433 if len(shadows) != 0:
1434 locs = [unforgeableMember.location] + [s.location for s in shadows]
1435 raise WebIDLError(
1436 "Interface %s shadows [LegacyUnforgeable] "
1437 "members of %s"
1438 % (self.identifier.name, ancestor.identifier.name),
1439 locs,
1441 # And now just stick it in our members, since we won't be
1442 # inheriting this down the proto chain. If we really cared we
1443 # could try to do something where we set up the unforgeable
1444 # attributes/methods of ancestor interfaces, with their
1445 # corresponding getters, on our interface, but that gets pretty
1446 # complicated and seems unnecessary.
1447 self.members.append(unforgeableMember)
1449 # At this point, we have all of our members. If the current interface
1450 # uses maplike/setlike, check for collisions anywhere in the current
1451 # interface or higher in the inheritance chain.
1452 if self.maplikeOrSetlikeOrIterable:
1453 testInterface = self
1454 isAncestor = False
1455 while testInterface:
1456 self.maplikeOrSetlikeOrIterable.checkCollisions(
1457 testInterface.members, isAncestor
1459 isAncestor = True
1460 testInterface = testInterface.parent
1462 # Ensure that there's at most one of each {named,indexed}
1463 # {getter,setter,deleter}, at most one stringifier,
1464 # and at most one legacycaller. Note that this last is not
1465 # quite per spec, but in practice no one overloads
1466 # legacycallers. Also note that in practice we disallow
1467 # indexed deleters, but it simplifies some other code to
1468 # treat deleter analogously to getter/setter by
1469 # prefixing it with "named".
1470 specialMembersSeen = {}
1471 for member in self.members:
1472 if not member.isMethod():
1473 continue
1475 if member.isGetter():
1476 memberType = "getters"
1477 elif member.isSetter():
1478 memberType = "setters"
1479 elif member.isDeleter():
1480 memberType = "deleters"
1481 elif member.isStringifier():
1482 memberType = "stringifiers"
1483 elif member.isLegacycaller():
1484 memberType = "legacycallers"
1485 else:
1486 continue
1488 if memberType != "stringifiers" and memberType != "legacycallers":
1489 if member.isNamed():
1490 memberType = "named " + memberType
1491 else:
1492 assert member.isIndexed()
1493 memberType = "indexed " + memberType
1495 if memberType in specialMembersSeen:
1496 raise WebIDLError(
1497 "Multiple " + memberType + " on %s" % (self),
1499 self.location,
1500 specialMembersSeen[memberType].location,
1501 member.location,
1505 specialMembersSeen[memberType] = member
1507 if self.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
1508 # Check that we have a named getter.
1509 if "named getters" not in specialMembersSeen:
1510 raise WebIDLError(
1511 "Interface with [LegacyUnenumerableNamedProperties] does "
1512 "not have a named getter",
1513 [self.location],
1515 ancestor = self.parent
1516 while ancestor:
1517 if ancestor.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
1518 raise WebIDLError(
1519 "Interface with [LegacyUnenumerableNamedProperties] "
1520 "inherits from another interface with "
1521 "[LegacyUnenumerableNamedProperties]",
1522 [self.location, ancestor.location],
1524 ancestor = ancestor.parent
1526 if self._isOnGlobalProtoChain:
1527 # Make sure we have no named setters or deleters
1528 for memberType in ["setter", "deleter"]:
1529 memberId = "named " + memberType + "s"
1530 if memberId in specialMembersSeen:
1531 raise WebIDLError(
1532 "Interface with [Global] has a named %s" % memberType,
1533 [self.location, specialMembersSeen[memberId].location],
1535 # Make sure we're not [LegacyOverrideBuiltIns]
1536 if self.getExtendedAttribute("LegacyOverrideBuiltIns"):
1537 raise WebIDLError(
1538 "Interface with [Global] also has " "[LegacyOverrideBuiltIns]",
1539 [self.location],
1541 # Mark all of our ancestors as being on the global's proto chain too
1542 parent = self.parent
1543 while parent:
1544 # Must not inherit from an interface with [LegacyOverrideBuiltIns]
1545 if parent.getExtendedAttribute("LegacyOverrideBuiltIns"):
1546 raise WebIDLError(
1547 "Interface with [Global] inherits from "
1548 "interface with [LegacyOverrideBuiltIns]",
1549 [self.location, parent.location],
1551 parent._isOnGlobalProtoChain = True
1552 parent = parent.parent
1554 def validate(self):
1555 def checkDuplicateNames(member, name, attributeName):
1556 for m in self.members:
1557 if m.identifier.name == name:
1558 raise WebIDLError(
1559 "[%s=%s] has same name as interface member"
1560 % (attributeName, name),
1561 [member.location, m.location],
1563 if m.isMethod() and m != member and name in m.aliases:
1564 raise WebIDLError(
1565 "conflicting [%s=%s] definitions" % (attributeName, name),
1566 [member.location, m.location],
1568 if m.isAttr() and m != member and name in m.bindingAliases:
1569 raise WebIDLError(
1570 "conflicting [%s=%s] definitions" % (attributeName, name),
1571 [member.location, m.location],
1574 # We also don't support inheriting from unforgeable interfaces.
1575 if self.getExtendedAttribute("LegacyUnforgeable") and self.hasChildInterfaces():
1576 locations = [self.location] + list(
1577 i.location for i in self.interfacesBasedOnSelf if i.parent == self
1579 raise WebIDLError(
1580 "%s is an unforgeable ancestor interface" % self.identifier.name,
1581 locations,
1584 ctor = self.ctor()
1585 if ctor is not None:
1586 ctor.validate()
1587 for namedCtor in self.legacyFactoryFunctions:
1588 namedCtor.validate()
1590 indexedGetter = None
1591 hasLengthAttribute = False
1592 for member in self.members:
1593 member.validate()
1595 if self.isCallback() and member.getExtendedAttribute("Replaceable"):
1596 raise WebIDLError(
1597 "[Replaceable] used on an attribute on "
1598 "interface %s which is a callback interface" % self.identifier.name,
1599 [self.location, member.location],
1602 # Check that PutForwards refers to another attribute and that no
1603 # cycles exist in forwarded assignments. Also check for a
1604 # integer-typed "length" attribute.
1605 if member.isAttr():
1606 if member.identifier.name == "length" and member.type.isInteger():
1607 hasLengthAttribute = True
1609 iface = self
1610 attr = member
1611 putForwards = attr.getExtendedAttribute("PutForwards")
1612 if putForwards and self.isCallback():
1613 raise WebIDLError(
1614 "[PutForwards] used on an attribute "
1615 "on interface %s which is a callback "
1616 "interface" % self.identifier.name,
1617 [self.location, member.location],
1620 while putForwards is not None:
1621 forwardIface = attr.type.unroll().inner
1622 fowardAttr = None
1624 for forwardedMember in forwardIface.members:
1625 if (
1626 not forwardedMember.isAttr()
1627 or forwardedMember.identifier.name != putForwards[0]
1629 continue
1630 if forwardedMember == member:
1631 raise WebIDLError(
1632 "Cycle detected in forwarded "
1633 "assignments for attribute %s on "
1634 "%s" % (member.identifier.name, self),
1635 [member.location],
1637 fowardAttr = forwardedMember
1638 break
1640 if fowardAttr is None:
1641 raise WebIDLError(
1642 "Attribute %s on %s forwards to "
1643 "missing attribute %s"
1644 % (attr.identifier.name, iface, putForwards),
1645 [attr.location],
1648 iface = forwardIface
1649 attr = fowardAttr
1650 putForwards = attr.getExtendedAttribute("PutForwards")
1652 # Check that the name of an [Alias] doesn't conflict with an
1653 # interface member and whether we support indexed properties.
1654 if member.isMethod():
1655 if member.isGetter() and member.isIndexed():
1656 indexedGetter = member
1658 for alias in member.aliases:
1659 if self.isOnGlobalProtoChain():
1660 raise WebIDLError(
1661 "[Alias] must not be used on a "
1662 "[Global] interface operation",
1663 [member.location],
1665 if (
1666 member.getExtendedAttribute("Exposed")
1667 or member.getExtendedAttribute("ChromeOnly")
1668 or member.getExtendedAttribute("Pref")
1669 or member.getExtendedAttribute("Func")
1670 or member.getExtendedAttribute("Trial")
1671 or member.getExtendedAttribute("SecureContext")
1673 raise WebIDLError(
1674 "[Alias] must not be used on a "
1675 "conditionally exposed operation",
1676 [member.location],
1678 if member.isStatic():
1679 raise WebIDLError(
1680 "[Alias] must not be used on a " "static operation",
1681 [member.location],
1683 if member.isIdentifierLess():
1684 raise WebIDLError(
1685 "[Alias] must not be used on an "
1686 "identifierless operation",
1687 [member.location],
1689 if member.isLegacyUnforgeable():
1690 raise WebIDLError(
1691 "[Alias] must not be used on an "
1692 "[LegacyUnforgeable] operation",
1693 [member.location],
1696 checkDuplicateNames(member, alias, "Alias")
1698 # Check that the name of a [BindingAlias] doesn't conflict with an
1699 # interface member.
1700 if member.isAttr():
1701 for bindingAlias in member.bindingAliases:
1702 checkDuplicateNames(member, bindingAlias, "BindingAlias")
1704 # Conditional exposure makes no sense for interfaces with no
1705 # interface object.
1706 # And SecureContext makes sense for interfaces with no interface object,
1707 # since it is also propagated to interface members.
1708 if (
1709 self.isExposedConditionally(exclusions=["SecureContext"])
1710 and not self.hasInterfaceObject()
1712 raise WebIDLError(
1713 "Interface with no interface object is " "exposed conditionally",
1714 [self.location],
1717 # Value iterators are only allowed on interfaces with indexed getters,
1718 # and pair iterators are only allowed on interfaces without indexed
1719 # getters.
1720 if self.isIterable():
1721 iterableDecl = self.maplikeOrSetlikeOrIterable
1722 if iterableDecl.isValueIterator():
1723 if not indexedGetter:
1724 raise WebIDLError(
1725 "Interface with value iterator does not "
1726 "support indexed properties",
1727 [self.location, iterableDecl.location],
1730 if iterableDecl.valueType != indexedGetter.signatures()[0][0]:
1731 raise WebIDLError(
1732 "Iterable type does not match indexed " "getter type",
1733 [iterableDecl.location, indexedGetter.location],
1736 if not hasLengthAttribute:
1737 raise WebIDLError(
1738 "Interface with value iterator does not "
1739 'have an integer-typed "length" attribute',
1740 [self.location, iterableDecl.location],
1742 else:
1743 assert iterableDecl.isPairIterator()
1744 if indexedGetter:
1745 raise WebIDLError(
1746 "Interface with pair iterator supports " "indexed properties",
1747 [self.location, iterableDecl.location, indexedGetter.location],
1750 if indexedGetter and not hasLengthAttribute:
1751 raise WebIDLError(
1752 "Interface with an indexed getter does not have "
1753 'an integer-typed "length" attribute',
1754 [self.location, indexedGetter.location],
1757 def setCallback(self, value):
1758 self._callback = value
1760 def isCallback(self):
1761 return self._callback
1763 def isSingleOperationInterface(self):
1764 assert self.isCallback() or self.isJSImplemented()
1765 return (
1766 # JS-implemented things should never need the
1767 # this-handling weirdness of single-operation interfaces.
1768 not self.isJSImplemented()
1770 # Not inheriting from another interface
1771 not self.parent
1773 # No attributes of any kinds
1774 not any(m.isAttr() for m in self.members)
1776 # There is at least one regular operation, and all regular
1777 # operations have the same identifier
1778 len(
1779 set(
1780 m.identifier.name
1781 for m in self.members
1782 if m.isMethod() and not m.isStatic()
1785 == 1
1788 def inheritanceDepth(self):
1789 depth = 0
1790 parent = self.parent
1791 while parent:
1792 depth = depth + 1
1793 parent = parent.parent
1794 return depth
1796 def hasConstants(self):
1797 return any(m.isConst() for m in self.members)
1799 def hasInterfaceObject(self):
1800 if self.isCallback():
1801 return self.hasConstants()
1802 return not hasattr(self, "_noInterfaceObject")
1804 def hasInterfacePrototypeObject(self):
1805 return (
1806 not self.isCallback()
1807 and not self.isNamespace()
1808 and self.getUserData("hasConcreteDescendant", False)
1811 def addIncludedMixin(self, includedMixin):
1812 assert isinstance(includedMixin, IDLInterfaceMixin)
1813 self.includedMixins.add(includedMixin)
1815 def getInheritedInterfaces(self):
1817 Returns a list of the interfaces this interface inherits from
1818 (not including this interface itself). The list is in order
1819 from most derived to least derived.
1821 assert self._finished
1822 if not self.parent:
1823 return []
1824 parentInterfaces = self.parent.getInheritedInterfaces()
1825 parentInterfaces.insert(0, self.parent)
1826 return parentInterfaces
1828 def findInterfaceLoopPoint(self, otherInterface):
1830 Finds an interface amongst our ancestors that inherits from otherInterface.
1831 If there is no such interface, returns None.
1833 if self.parent:
1834 if self.parent == otherInterface:
1835 return self
1836 loopPoint = self.parent.findInterfaceLoopPoint(otherInterface)
1837 if loopPoint:
1838 return loopPoint
1839 return None
1841 def setNonPartial(self, location, parent, members):
1842 assert not parent or isinstance(parent, IDLIdentifierPlaceholder)
1843 IDLInterfaceOrInterfaceMixinOrNamespace.setNonPartial(self, location, members)
1844 assert not self.parent
1845 self.parent = parent
1847 def getJSImplementation(self):
1848 classId = self.getExtendedAttribute("JSImplementation")
1849 if not classId:
1850 return classId
1851 assert isinstance(classId, list)
1852 assert len(classId) == 1
1853 return classId[0]
1855 def isJSImplemented(self):
1856 return bool(self.getJSImplementation())
1858 def hasProbablyShortLivingWrapper(self):
1859 current = self
1860 while current:
1861 if current.getExtendedAttribute("ProbablyShortLivingWrapper"):
1862 return True
1863 current = current.parent
1864 return False
1866 def hasChildInterfaces(self):
1867 return self._hasChildInterfaces
1869 def isOnGlobalProtoChain(self):
1870 return self._isOnGlobalProtoChain
1872 def _getDependentObjects(self):
1873 deps = set(self.members)
1874 deps.update(self.includedMixins)
1875 if self.parent:
1876 deps.add(self.parent)
1877 return deps
1879 def hasMembersInSlots(self):
1880 return self._ownMembersInSlots != 0
1882 conditionExtendedAttributes = [
1883 "Pref",
1884 "ChromeOnly",
1885 "Func",
1886 "Trial",
1887 "SecureContext",
1890 def isExposedConditionally(self, exclusions=[]):
1891 return any(
1892 ((a not in exclusions) and self.getExtendedAttribute(a))
1893 for a in self.conditionExtendedAttributes
1897 class IDLInterface(IDLInterfaceOrNamespace):
1898 def __init__(
1899 self,
1900 location,
1901 parentScope,
1902 name,
1903 parent,
1904 members,
1905 isKnownNonPartial,
1906 classNameOverride=None,
1908 IDLInterfaceOrNamespace.__init__(
1909 self, location, parentScope, name, parent, members, isKnownNonPartial
1911 self.classNameOverride = classNameOverride
1913 def __str__(self):
1914 return "Interface '%s'" % self.identifier.name
1916 def isInterface(self):
1917 return True
1919 def getClassName(self):
1920 if self.classNameOverride:
1921 return self.classNameOverride
1922 return IDLInterfaceOrNamespace.getClassName(self)
1924 def addExtendedAttributes(self, attrs):
1925 for attr in attrs:
1926 identifier = attr.identifier()
1928 # Special cased attrs
1929 if identifier == "TreatNonCallableAsNull":
1930 raise WebIDLError(
1931 "TreatNonCallableAsNull cannot be specified on interfaces",
1932 [attr.location, self.location],
1934 if identifier == "LegacyTreatNonObjectAsNull":
1935 raise WebIDLError(
1936 "LegacyTreatNonObjectAsNull cannot be specified on interfaces",
1937 [attr.location, self.location],
1939 elif identifier == "LegacyNoInterfaceObject":
1940 if not attr.noArguments():
1941 raise WebIDLError(
1942 "[LegacyNoInterfaceObject] must take no arguments",
1943 [attr.location],
1946 self._noInterfaceObject = True
1947 elif identifier == "LegacyFactoryFunction":
1948 if not attr.hasValue():
1949 raise WebIDLError(
1951 "LegacyFactoryFunction must either take an "
1952 "identifier or take a named argument list"
1954 [attr.location],
1957 args = attr.args() if attr.hasArgs() else []
1959 method = IDLConstructor(attr.location, args, attr.value())
1960 method.reallyInit(self)
1962 # Legacy factory functions are always assumed to be able to
1963 # throw (since there's no way to indicate otherwise).
1964 method.addExtendedAttributes(
1965 [IDLExtendedAttribute(self.location, ("Throws",))]
1968 # We need to detect conflicts for LegacyFactoryFunctions across
1969 # interfaces. We first call resolve on the parentScope,
1970 # which will merge all LegacyFactoryFunctions with the same
1971 # identifier accross interfaces as overloads.
1972 method.resolve(self.parentScope)
1974 # Then we look up the identifier on the parentScope. If the
1975 # result is the same as the method we're adding then it
1976 # hasn't been added as an overload and it's the first time
1977 # we've encountered a LegacyFactoryFunction with that identifier.
1978 # If the result is not the same as the method we're adding
1979 # then it has been added as an overload and we need to check
1980 # whether the result is actually one of our existing
1981 # LegacyFactoryFunctions.
1982 newMethod = self.parentScope.lookupIdentifier(method.identifier)
1983 if newMethod == method:
1984 self.legacyFactoryFunctions.append(method)
1985 elif newMethod not in self.legacyFactoryFunctions:
1986 raise WebIDLError(
1987 "LegacyFactoryFunction conflicts with a "
1988 "LegacyFactoryFunction of a different interface",
1989 [method.location, newMethod.location],
1991 elif identifier == "ExceptionClass":
1992 if not attr.noArguments():
1993 raise WebIDLError(
1994 "[ExceptionClass] must take no arguments", [attr.location]
1996 if self.parent:
1997 raise WebIDLError(
1998 "[ExceptionClass] must not be specified on "
1999 "an interface with inherited interfaces",
2000 [attr.location, self.location],
2002 elif identifier == "Global":
2003 if attr.hasValue():
2004 self.globalNames = [attr.value()]
2005 elif attr.hasArgs():
2006 self.globalNames = attr.args()
2007 else:
2008 self.globalNames = [self.identifier.name]
2009 self.parentScope.addIfaceGlobalNames(
2010 self.identifier.name, self.globalNames
2012 self._isOnGlobalProtoChain = True
2013 elif identifier == "LegacyWindowAlias":
2014 if attr.hasValue():
2015 self.legacyWindowAliases = [attr.value()]
2016 elif attr.hasArgs():
2017 self.legacyWindowAliases = attr.args()
2018 else:
2019 raise WebIDLError(
2020 "[%s] must either take an identifier "
2021 "or take an identifier list" % identifier,
2022 [attr.location],
2024 for alias in self.legacyWindowAliases:
2025 unresolved = IDLUnresolvedIdentifier(attr.location, alias)
2026 IDLObjectWithIdentifier(attr.location, self.parentScope, unresolved)
2027 elif identifier == "SecureContext":
2028 if not attr.noArguments():
2029 raise WebIDLError(
2030 "[%s] must take no arguments" % identifier, [attr.location]
2032 # This gets propagated to all our members.
2033 for member in self.members:
2034 if member.getExtendedAttribute("SecureContext"):
2035 raise WebIDLError(
2036 "[SecureContext] specified on both "
2037 "an interface member and on the "
2038 "interface itself",
2039 [member.location, attr.location],
2041 member.addExtendedAttributes([attr])
2042 elif (
2043 identifier == "NeedResolve"
2044 or identifier == "LegacyOverrideBuiltIns"
2045 or identifier == "ChromeOnly"
2046 or identifier == "LegacyUnforgeable"
2047 or identifier == "LegacyEventInit"
2048 or identifier == "ProbablyShortLivingWrapper"
2049 or identifier == "LegacyUnenumerableNamedProperties"
2050 or identifier == "RunConstructorInCallerCompartment"
2051 or identifier == "WantsEventListenerHooks"
2052 or identifier == "Serializable"
2054 # Known extended attributes that do not take values
2055 if not attr.noArguments():
2056 raise WebIDLError(
2057 "[%s] must take no arguments" % identifier, [attr.location]
2059 elif identifier == "Exposed":
2060 convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
2061 elif (
2062 identifier == "Pref"
2063 or identifier == "JSImplementation"
2064 or identifier == "HeaderFile"
2065 or identifier == "Func"
2066 or identifier == "Trial"
2067 or identifier == "Deprecated"
2069 # Known extended attributes that take a string value
2070 if not attr.hasValue():
2071 raise WebIDLError(
2072 "[%s] must have a value" % identifier, [attr.location]
2074 elif identifier == "InstrumentedProps":
2075 # Known extended attributes that take a list
2076 if not attr.hasArgs():
2077 raise WebIDLError(
2078 "[%s] must have arguments" % identifier, [attr.location]
2080 else:
2081 raise WebIDLError(
2082 "Unknown extended attribute %s on interface" % identifier,
2083 [attr.location],
2086 attrlist = attr.listValue()
2087 self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
2089 def validate(self):
2090 IDLInterfaceOrNamespace.validate(self)
2091 if self.parent and self.isSerializable() and not self.parent.isSerializable():
2092 raise WebIDLError(
2093 "Serializable interface inherits from non-serializable "
2094 "interface. Per spec, that means the object should not be "
2095 "serializable, so chances are someone made a mistake here "
2096 "somewhere.",
2097 [self.location, self.parent.location],
2100 def isSerializable(self):
2101 return self.getExtendedAttribute("Serializable")
2103 def setNonPartial(self, location, parent, members):
2104 # Before we do anything else, finish initializing any constructors that
2105 # might be in "members", so we don't have partially-initialized objects
2106 # hanging around. We couldn't do it before now because we needed to have
2107 # to have the IDLInterface on hand to properly set the return type.
2108 for member in members:
2109 if isinstance(member, IDLConstructor):
2110 member.reallyInit(self)
2112 IDLInterfaceOrNamespace.setNonPartial(self, location, parent, members)
2115 class IDLNamespace(IDLInterfaceOrNamespace):
2116 def __init__(self, location, parentScope, name, members, isKnownNonPartial):
2117 IDLInterfaceOrNamespace.__init__(
2118 self, location, parentScope, name, None, members, isKnownNonPartial
2121 def __str__(self):
2122 return "Namespace '%s'" % self.identifier.name
2124 def isNamespace(self):
2125 return True
2127 def addExtendedAttributes(self, attrs):
2128 # The set of things namespaces support is small enough it's simpler
2129 # to factor out into a separate method than it is to sprinkle
2130 # isNamespace() checks all through
2131 # IDLInterfaceOrNamespace.addExtendedAttributes.
2132 for attr in attrs:
2133 identifier = attr.identifier()
2135 if identifier == "Exposed":
2136 convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
2137 elif identifier == "ClassString":
2138 # Takes a string value to override the default "Object" if
2139 # desired.
2140 if not attr.hasValue():
2141 raise WebIDLError(
2142 "[%s] must have a value" % identifier, [attr.location]
2144 elif identifier == "ProtoObjectHack" or identifier == "ChromeOnly":
2145 if not attr.noArguments():
2146 raise WebIDLError(
2147 "[%s] must not have arguments" % identifier, [attr.location]
2149 elif (
2150 identifier == "Pref"
2151 or identifier == "HeaderFile"
2152 or identifier == "Func"
2153 or identifier == "Trial"
2155 # Known extended attributes that take a string value
2156 if not attr.hasValue():
2157 raise WebIDLError(
2158 "[%s] must have a value" % identifier, [attr.location]
2160 else:
2161 raise WebIDLError(
2162 "Unknown extended attribute %s on namespace" % identifier,
2163 [attr.location],
2166 attrlist = attr.listValue()
2167 self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
2169 def isSerializable(self):
2170 return False
2173 class IDLDictionary(IDLObjectWithScope):
2174 def __init__(self, location, parentScope, name, parent, members):
2175 assert isinstance(parentScope, IDLScope)
2176 assert isinstance(name, IDLUnresolvedIdentifier)
2177 assert not parent or isinstance(parent, IDLIdentifierPlaceholder)
2179 self.parent = parent
2180 self._finished = False
2181 self.members = list(members)
2182 self._partialDictionaries = []
2183 self._extendedAttrDict = {}
2184 self.needsConversionToJS = False
2185 self.needsConversionFromJS = False
2187 IDLObjectWithScope.__init__(self, location, parentScope, name)
2189 def __str__(self):
2190 return "Dictionary '%s'" % self.identifier.name
2192 def isDictionary(self):
2193 return True
2195 def canBeEmpty(self):
2197 Returns true if this dictionary can be empty (that is, it has no
2198 required members and neither do any of its ancestors).
2200 return all(member.optional for member in self.members) and (
2201 not self.parent or self.parent.canBeEmpty()
2204 def finish(self, scope):
2205 if self._finished:
2206 return
2208 self._finished = True
2210 if self.parent:
2211 assert isinstance(self.parent, IDLIdentifierPlaceholder)
2212 oldParent = self.parent
2213 self.parent = self.parent.finish(scope)
2214 if not isinstance(self.parent, IDLDictionary):
2215 raise WebIDLError(
2216 "Dictionary %s has parent that is not a dictionary"
2217 % self.identifier.name,
2218 [oldParent.location, self.parent.location],
2221 # Make sure the parent resolves all its members before we start
2222 # looking at them.
2223 self.parent.finish(scope)
2225 # Now go ahead and merge in our partial dictionaries.
2226 for partial in self._partialDictionaries:
2227 partial.finish(scope)
2228 self.members.extend(partial.members)
2230 for member in self.members:
2231 member.resolve(self)
2232 if not member.isComplete():
2233 member.complete(scope)
2234 assert member.type.isComplete()
2236 # Members of a dictionary are sorted in lexicographic order,
2237 # unless the dictionary opts out.
2238 if not self.getExtendedAttribute("Unsorted"):
2239 self.members.sort(key=lambda x: x.identifier.name)
2241 inheritedMembers = []
2242 ancestor = self.parent
2243 while ancestor:
2244 if ancestor == self:
2245 raise WebIDLError(
2246 "Dictionary %s has itself as an ancestor" % self.identifier.name,
2247 [self.identifier.location],
2249 inheritedMembers.extend(ancestor.members)
2250 ancestor = ancestor.parent
2252 # Catch name duplication
2253 for inheritedMember in inheritedMembers:
2254 for member in self.members:
2255 if member.identifier.name == inheritedMember.identifier.name:
2256 raise WebIDLError(
2257 "Dictionary %s has two members with name %s"
2258 % (self.identifier.name, member.identifier.name),
2259 [member.location, inheritedMember.location],
2262 def validate(self):
2263 def typeContainsDictionary(memberType, dictionary):
2265 Returns a tuple whose:
2267 - First element is a Boolean value indicating whether
2268 memberType contains dictionary.
2270 - Second element is:
2271 A list of locations that leads from the type that was passed in
2272 the memberType argument, to the dictionary being validated,
2273 if the boolean value in the first element is True.
2275 None, if the boolean value in the first element is False.
2278 if (
2279 memberType.nullable()
2280 or memberType.isSequence()
2281 or memberType.isRecord()
2283 return typeContainsDictionary(memberType.inner, dictionary)
2285 if memberType.isDictionary():
2286 if memberType.inner == dictionary:
2287 return (True, [memberType.location])
2289 (contains, locations) = dictionaryContainsDictionary(
2290 memberType.inner, dictionary
2292 if contains:
2293 return (True, [memberType.location] + locations)
2295 if memberType.isUnion():
2296 for member in memberType.flatMemberTypes:
2297 (contains, locations) = typeContainsDictionary(member, dictionary)
2298 if contains:
2299 return (True, locations)
2301 return (False, None)
2303 def dictionaryContainsDictionary(dictMember, dictionary):
2304 for member in dictMember.members:
2305 (contains, locations) = typeContainsDictionary(member.type, dictionary)
2306 if contains:
2307 return (True, [member.location] + locations)
2309 if dictMember.parent:
2310 if dictMember.parent == dictionary:
2311 return (True, [dictMember.location])
2312 else:
2313 (contains, locations) = dictionaryContainsDictionary(
2314 dictMember.parent, dictionary
2316 if contains:
2317 return (True, [dictMember.location] + locations)
2319 return (False, None)
2321 for member in self.members:
2322 if member.type.isDictionary() and member.type.nullable():
2323 raise WebIDLError(
2324 "Dictionary %s has member with nullable "
2325 "dictionary type" % self.identifier.name,
2326 [member.location],
2328 (contains, locations) = typeContainsDictionary(member.type, self)
2329 if contains:
2330 raise WebIDLError(
2331 "Dictionary %s has member with itself as type."
2332 % self.identifier.name,
2333 [member.location] + locations,
2336 if member.type.isUndefined():
2337 raise WebIDLError(
2338 "Dictionary %s has member with undefined as its type."
2339 % self.identifier.name,
2340 [member.location],
2342 elif member.type.isUnion():
2343 for unionMember in member.type.unroll().flatMemberTypes:
2344 if unionMember.isUndefined():
2345 raise WebIDLError(
2346 "Dictionary %s has member with a union containing "
2347 "undefined as a type." % self.identifier.name,
2348 [unionMember.location],
2351 def getExtendedAttribute(self, name):
2352 return self._extendedAttrDict.get(name, None)
2354 def addExtendedAttributes(self, attrs):
2355 for attr in attrs:
2356 identifier = attr.identifier()
2358 if identifier == "GenerateInitFromJSON" or identifier == "GenerateInit":
2359 if not attr.noArguments():
2360 raise WebIDLError(
2361 "[%s] must not have arguments" % identifier, [attr.location]
2363 self.needsConversionFromJS = True
2364 elif (
2365 identifier == "GenerateConversionToJS" or identifier == "GenerateToJSON"
2367 if not attr.noArguments():
2368 raise WebIDLError(
2369 "[%s] must not have arguments" % identifier, [attr.location]
2371 # ToJSON methods require to-JS conversion, because we
2372 # implement ToJSON by converting to a JS object and
2373 # then using JSON.stringify.
2374 self.needsConversionToJS = True
2375 elif identifier == "Unsorted":
2376 if not attr.noArguments():
2377 raise WebIDLError(
2378 "[Unsorted] must take no arguments", [attr.location]
2380 else:
2381 raise WebIDLError(
2382 "[%s] extended attribute not allowed on "
2383 "dictionaries" % identifier,
2384 [attr.location],
2387 self._extendedAttrDict[identifier] = True
2389 def _getDependentObjects(self):
2390 deps = set(self.members)
2391 if self.parent:
2392 deps.add(self.parent)
2393 return deps
2395 def addPartialDictionary(self, partial):
2396 assert self.identifier.name == partial.identifier.name
2397 self._partialDictionaries.append(partial)
2400 class IDLEnum(IDLObjectWithIdentifier):
2401 def __init__(self, location, parentScope, name, values):
2402 assert isinstance(parentScope, IDLScope)
2403 assert isinstance(name, IDLUnresolvedIdentifier)
2405 if len(values) != len(set(values)):
2406 raise WebIDLError(
2407 "Enum %s has multiple identical strings" % name.name, [location]
2410 IDLObjectWithIdentifier.__init__(self, location, parentScope, name)
2411 self._values = values
2413 def values(self):
2414 return self._values
2416 def finish(self, scope):
2417 pass
2419 def validate(self):
2420 pass
2422 def isEnum(self):
2423 return True
2425 def addExtendedAttributes(self, attrs):
2426 if len(attrs) != 0:
2427 raise WebIDLError(
2428 "There are no extended attributes that are " "allowed on enums",
2429 [attrs[0].location, self.location],
2432 def _getDependentObjects(self):
2433 return set()
2436 class IDLType(IDLObject):
2437 Tags = enum(
2438 # The integer types
2439 "int8",
2440 "uint8",
2441 "int16",
2442 "uint16",
2443 "int32",
2444 "uint32",
2445 "int64",
2446 "uint64",
2447 # Additional primitive types
2448 "bool",
2449 "unrestricted_float",
2450 "float",
2451 "unrestricted_double",
2452 # "double" last primitive type to match IDLBuiltinType
2453 "double",
2454 # Other types
2455 "any",
2456 "undefined",
2457 "domstring",
2458 "bytestring",
2459 "usvstring",
2460 "utf8string",
2461 "jsstring",
2462 "object",
2463 # Funny stuff
2464 "interface",
2465 "dictionary",
2466 "enum",
2467 "callback",
2468 "union",
2469 "sequence",
2470 "record",
2471 "promise",
2472 "observablearray",
2475 def __init__(self, location, name):
2476 IDLObject.__init__(self, location)
2477 self.name = name
2478 self.builtin = False
2479 self.legacyNullToEmptyString = False
2480 self._clamp = False
2481 self._enforceRange = False
2482 self._allowShared = False
2483 self._extendedAttrDict = {}
2485 def __hash__(self):
2486 return (
2487 hash(self.builtin)
2488 + hash(self.name)
2489 + hash(self._clamp)
2490 + hash(self._enforceRange)
2491 + hash(self.legacyNullToEmptyString)
2492 + hash(self._allowShared)
2495 def __eq__(self, other):
2496 return (
2497 other
2498 and self.builtin == other.builtin
2499 and self.name == other.name
2500 and self._clamp == other.hasClamp()
2501 and self._enforceRange == other.hasEnforceRange()
2502 and self.legacyNullToEmptyString == other.legacyNullToEmptyString
2503 and self._allowShared == other.hasAllowShared()
2506 def __ne__(self, other):
2507 return not self == other
2509 def __str__(self):
2510 return str(self.name)
2512 def prettyName(self):
2514 A name that looks like what this type is named in the IDL spec. By default
2515 this is just our .name, but types that have more interesting spec
2516 representations should override this.
2518 return str(self.name)
2520 def isType(self):
2521 return True
2523 def nullable(self):
2524 return False
2526 def isPrimitive(self):
2527 return False
2529 def isBoolean(self):
2530 return False
2532 def isNumeric(self):
2533 return False
2535 def isString(self):
2536 return False
2538 def isByteString(self):
2539 return False
2541 def isDOMString(self):
2542 return False
2544 def isUSVString(self):
2545 return False
2547 def isUTF8String(self):
2548 return False
2550 def isJSString(self):
2551 return False
2553 def isUndefined(self):
2554 return False
2556 def isSequence(self):
2557 return False
2559 def isRecord(self):
2560 return False
2562 def isArrayBuffer(self):
2563 return False
2565 def isArrayBufferView(self):
2566 return False
2568 def isTypedArray(self):
2569 return False
2571 def isBufferSource(self):
2572 return self.isArrayBuffer() or self.isArrayBufferView() or self.isTypedArray()
2574 def isCallbackInterface(self):
2575 return False
2577 def isNonCallbackInterface(self):
2578 return False
2580 def isGeckoInterface(self):
2581 """Returns a boolean indicating whether this type is an 'interface'
2582 type that is implemented in Gecko. At the moment, this returns
2583 true for all interface types that are not types from the TypedArray
2584 spec."""
2585 return self.isInterface() and not self.isSpiderMonkeyInterface()
2587 def isSpiderMonkeyInterface(self):
2588 """Returns a boolean indicating whether this type is an 'interface'
2589 type that is implemented in SpiderMonkey."""
2590 return self.isInterface() and self.isBufferSource()
2592 def isAny(self):
2593 return self.tag() == IDLType.Tags.any
2595 def isObject(self):
2596 return self.tag() == IDLType.Tags.object
2598 def isPromise(self):
2599 return False
2601 def isComplete(self):
2602 return True
2604 def includesRestrictedFloat(self):
2605 return False
2607 def isFloat(self):
2608 return False
2610 def isUnrestricted(self):
2611 # Should only call this on float types
2612 assert self.isFloat()
2614 def isJSONType(self):
2615 return False
2617 def isObservableArray(self):
2618 return False
2620 def isDictionaryLike(self):
2621 return self.isDictionary() or self.isRecord() or self.isCallbackInterface()
2623 def hasClamp(self):
2624 return self._clamp
2626 def hasEnforceRange(self):
2627 return self._enforceRange
2629 def hasAllowShared(self):
2630 return self._allowShared
2632 def tag(self):
2633 assert False # Override me!
2635 def treatNonCallableAsNull(self):
2636 assert self.tag() == IDLType.Tags.callback
2637 return self.nullable() and self.inner.callback._treatNonCallableAsNull
2639 def treatNonObjectAsNull(self):
2640 assert self.tag() == IDLType.Tags.callback
2641 return self.nullable() and self.inner.callback._treatNonObjectAsNull
2643 def withExtendedAttributes(self, attrs):
2644 if len(attrs) > 0:
2645 raise WebIDLError(
2646 "Extended attributes on types only supported for builtins",
2647 [attrs[0].location, self.location],
2649 return self
2651 def getExtendedAttribute(self, name):
2652 return self._extendedAttrDict.get(name, None)
2654 def resolveType(self, parentScope):
2655 pass
2657 def unroll(self):
2658 return self
2660 def isDistinguishableFrom(self, other):
2661 raise TypeError(
2662 "Can't tell whether a generic type is or is not "
2663 "distinguishable from other things"
2666 def isExposedInAllOf(self, exposureSet):
2667 return True
2670 class IDLUnresolvedType(IDLType):
2672 Unresolved types are interface types
2675 def __init__(self, location, name, attrs=[]):
2676 IDLType.__init__(self, location, name)
2677 self.extraTypeAttributes = attrs
2679 def isComplete(self):
2680 return False
2682 def complete(self, scope):
2683 obj = None
2684 try:
2685 obj = scope._lookupIdentifier(self.name)
2686 except Exception:
2687 raise WebIDLError("Unresolved type '%s'." % self.name, [self.location])
2689 assert obj
2690 assert not obj.isType()
2691 if obj.isTypedef():
2692 assert self.name.name == obj.identifier.name
2693 typedefType = IDLTypedefType(self.location, obj.innerType, obj.identifier)
2694 assert not typedefType.isComplete()
2695 return typedefType.complete(scope).withExtendedAttributes(
2696 self.extraTypeAttributes
2698 elif obj.isCallback() and not obj.isInterface():
2699 assert self.name.name == obj.identifier.name
2700 return IDLCallbackType(self.location, obj)
2702 return IDLWrapperType(self.location, obj)
2704 def withExtendedAttributes(self, attrs):
2705 return IDLUnresolvedType(self.location, self.name, attrs)
2707 def isDistinguishableFrom(self, other):
2708 raise TypeError(
2709 "Can't tell whether an unresolved type is or is not "
2710 "distinguishable from other things"
2714 class IDLParametrizedType(IDLType):
2715 def __init__(self, location, name, innerType):
2716 IDLType.__init__(self, location, name)
2717 self.builtin = False
2718 self.inner = innerType
2720 def includesRestrictedFloat(self):
2721 return self.inner.includesRestrictedFloat()
2723 def resolveType(self, parentScope):
2724 assert isinstance(parentScope, IDLScope)
2725 self.inner.resolveType(parentScope)
2727 def isComplete(self):
2728 return self.inner.isComplete()
2730 def unroll(self):
2731 return self.inner.unroll()
2733 def _getDependentObjects(self):
2734 return self.inner._getDependentObjects()
2737 class IDLNullableType(IDLParametrizedType):
2738 def __init__(self, location, innerType):
2739 assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any]
2741 IDLParametrizedType.__init__(self, location, None, innerType)
2743 def __hash__(self):
2744 return hash(self.inner)
2746 def __eq__(self, other):
2747 return isinstance(other, IDLNullableType) and self.inner == other.inner
2749 def __str__(self):
2750 return self.inner.__str__() + "OrNull"
2752 def prettyName(self):
2753 return self.inner.prettyName() + "?"
2755 def nullable(self):
2756 return True
2758 def isCallback(self):
2759 return self.inner.isCallback()
2761 def isPrimitive(self):
2762 return self.inner.isPrimitive()
2764 def isBoolean(self):
2765 return self.inner.isBoolean()
2767 def isNumeric(self):
2768 return self.inner.isNumeric()
2770 def isString(self):
2771 return self.inner.isString()
2773 def isByteString(self):
2774 return self.inner.isByteString()
2776 def isDOMString(self):
2777 return self.inner.isDOMString()
2779 def isUSVString(self):
2780 return self.inner.isUSVString()
2782 def isUTF8String(self):
2783 return self.inner.isUTF8String()
2785 def isJSString(self):
2786 return self.inner.isJSString()
2788 def isFloat(self):
2789 return self.inner.isFloat()
2791 def isUnrestricted(self):
2792 return self.inner.isUnrestricted()
2794 def isInteger(self):
2795 return self.inner.isInteger()
2797 def isUndefined(self):
2798 return self.inner.isUndefined()
2800 def isSequence(self):
2801 return self.inner.isSequence()
2803 def isRecord(self):
2804 return self.inner.isRecord()
2806 def isArrayBuffer(self):
2807 return self.inner.isArrayBuffer()
2809 def isArrayBufferView(self):
2810 return self.inner.isArrayBufferView()
2812 def isTypedArray(self):
2813 return self.inner.isTypedArray()
2815 def isDictionary(self):
2816 return self.inner.isDictionary()
2818 def isInterface(self):
2819 return self.inner.isInterface()
2821 def isPromise(self):
2822 # There is no such thing as a nullable Promise.
2823 assert not self.inner.isPromise()
2824 return False
2826 def isCallbackInterface(self):
2827 return self.inner.isCallbackInterface()
2829 def isNonCallbackInterface(self):
2830 return self.inner.isNonCallbackInterface()
2832 def isEnum(self):
2833 return self.inner.isEnum()
2835 def isUnion(self):
2836 return self.inner.isUnion()
2838 def isJSONType(self):
2839 return self.inner.isJSONType()
2841 def isObservableArray(self):
2842 return self.inner.isObservableArray()
2844 def hasClamp(self):
2845 return self.inner.hasClamp()
2847 def hasEnforceRange(self):
2848 return self.inner.hasEnforceRange()
2850 def hasAllowShared(self):
2851 return self.inner.hasAllowShared()
2853 def isComplete(self):
2854 return self.name is not None
2856 def tag(self):
2857 return self.inner.tag()
2859 def complete(self, scope):
2860 if not self.inner.isComplete():
2861 self.inner = self.inner.complete(scope)
2862 assert self.inner.isComplete()
2864 if self.inner.nullable():
2865 raise WebIDLError(
2866 "The inner type of a nullable type must not be a nullable type",
2867 [self.location, self.inner.location],
2869 if self.inner.isUnion():
2870 if self.inner.hasNullableType:
2871 raise WebIDLError(
2872 "The inner type of a nullable type must not "
2873 "be a union type that itself has a nullable "
2874 "type as a member type",
2875 [self.location],
2877 if self.inner.isDOMString():
2878 if self.inner.legacyNullToEmptyString:
2879 raise WebIDLError(
2880 "[LegacyNullToEmptyString] not allowed on a nullable DOMString",
2881 [self.location, self.inner.location],
2883 if self.inner.isObservableArray():
2884 raise WebIDLError(
2885 "The inner type of a nullable type must not be an ObservableArray type",
2886 [self.location, self.inner.location],
2889 self.name = self.inner.name + "OrNull"
2890 return self
2892 def isDistinguishableFrom(self, other):
2893 if (
2894 other.nullable()
2895 or other.isDictionary()
2896 or (
2897 other.isUnion() and (other.hasNullableType or other.hasDictionaryType())
2900 # Can't tell which type null should become
2901 return False
2902 return self.inner.isDistinguishableFrom(other)
2904 def withExtendedAttributes(self, attrs):
2905 # See https://github.com/heycam/webidl/issues/827#issuecomment-565131350
2906 # Allowing extended attributes to apply to a nullable type is an intermediate solution.
2907 # A potential longer term solution is to introduce a null type and get rid of nullables.
2908 # For example, we could do `([Clamp] long or null) foo` in the future.
2909 return IDLNullableType(self.location, self.inner.withExtendedAttributes(attrs))
2912 class IDLSequenceType(IDLParametrizedType):
2913 def __init__(self, location, parameterType):
2914 assert not parameterType.isUndefined()
2916 IDLParametrizedType.__init__(self, location, parameterType.name, parameterType)
2917 # Need to set self.name up front if our inner type is already complete,
2918 # since in that case our .complete() won't be called.
2919 if self.inner.isComplete():
2920 self.name = self.inner.name + "Sequence"
2922 def __hash__(self):
2923 return hash(self.inner)
2925 def __eq__(self, other):
2926 return isinstance(other, IDLSequenceType) and self.inner == other.inner
2928 def __str__(self):
2929 return self.inner.__str__() + "Sequence"
2931 def prettyName(self):
2932 return "sequence<%s>" % self.inner.prettyName()
2934 def isSequence(self):
2935 return True
2937 def isJSONType(self):
2938 return self.inner.isJSONType()
2940 def tag(self):
2941 return IDLType.Tags.sequence
2943 def complete(self, scope):
2944 if self.inner.isObservableArray():
2945 raise WebIDLError(
2946 "The inner type of a sequence type must not be an ObservableArray type",
2947 [self.location, self.inner.location],
2950 self.inner = self.inner.complete(scope)
2951 self.name = self.inner.name + "Sequence"
2952 return self
2954 def isDistinguishableFrom(self, other):
2955 if other.isPromise():
2956 return False
2957 if other.isUnion():
2958 # Just forward to the union; it'll deal
2959 return other.isDistinguishableFrom(self)
2960 return (
2961 other.isUndefined()
2962 or other.isPrimitive()
2963 or other.isString()
2964 or other.isEnum()
2965 or other.isInterface()
2966 or other.isDictionary()
2967 or other.isCallback()
2968 or other.isRecord()
2972 class IDLRecordType(IDLParametrizedType):
2973 def __init__(self, location, keyType, valueType):
2974 assert keyType.isString()
2975 assert keyType.isComplete()
2977 if valueType.isUndefined():
2978 raise WebIDLError(
2979 "We don't support undefined as a Record's values' type",
2980 [location, valueType.location],
2983 IDLParametrizedType.__init__(self, location, valueType.name, valueType)
2984 self.keyType = keyType
2986 # Need to set self.name up front if our inner type is already complete,
2987 # since in that case our .complete() won't be called.
2988 if self.inner.isComplete():
2989 self.name = self.keyType.name + self.inner.name + "Record"
2991 def __hash__(self):
2992 return hash(self.inner)
2994 def __eq__(self, other):
2995 return isinstance(other, IDLRecordType) and self.inner == other.inner
2997 def __str__(self):
2998 return self.keyType.__str__() + self.inner.__str__() + "Record"
3000 def prettyName(self):
3001 return "record<%s, %s>" % (self.keyType.prettyName(), self.inner.prettyName())
3003 def isRecord(self):
3004 return True
3006 def isJSONType(self):
3007 return self.inner.isJSONType()
3009 def tag(self):
3010 return IDLType.Tags.record
3012 def complete(self, scope):
3013 if self.inner.isObservableArray():
3014 raise WebIDLError(
3015 "The value type of a record type must not be an ObservableArray type",
3016 [self.location, self.inner.location],
3019 self.inner = self.inner.complete(scope)
3020 self.name = self.keyType.name + self.inner.name + "Record"
3021 return self
3023 def unroll(self):
3024 # We do not unroll our inner. Just stop at ourselves. That
3025 # lets us add headers for both ourselves and our inner as
3026 # needed.
3027 return self
3029 def isDistinguishableFrom(self, other):
3030 if other.isPromise():
3031 return False
3032 if other.isUnion():
3033 # Just forward to the union; it'll deal
3034 return other.isDistinguishableFrom(self)
3035 return (
3036 other.isPrimitive()
3037 or other.isString()
3038 or other.isEnum()
3039 or other.isNonCallbackInterface()
3040 or other.isSequence()
3043 def isExposedInAllOf(self, exposureSet):
3044 return self.inner.unroll().isExposedInAllOf(exposureSet)
3047 class IDLObservableArrayType(IDLParametrizedType):
3048 def __init__(self, location, innerType):
3049 assert not innerType.isUndefined()
3050 IDLParametrizedType.__init__(self, location, None, innerType)
3052 def __hash__(self):
3053 return hash(self.inner)
3055 def __eq__(self, other):
3056 return isinstance(other, IDLObservableArrayType) and self.inner == other.inner
3058 def __str__(self):
3059 return self.inner.__str__() + "ObservableArray"
3061 def prettyName(self):
3062 return "ObservableArray<%s>" % self.inner.prettyName()
3064 def isJSONType(self):
3065 return self.inner.isJSONType()
3067 def isObservableArray(self):
3068 return True
3070 def isComplete(self):
3071 return self.name is not None
3073 def tag(self):
3074 return IDLType.Tags.observablearray
3076 def complete(self, scope):
3077 if not self.inner.isComplete():
3078 self.inner = self.inner.complete(scope)
3079 assert self.inner.isComplete()
3081 if self.inner.isDictionary():
3082 raise WebIDLError(
3083 "The inner type of an ObservableArray type must not "
3084 "be a dictionary type",
3085 [self.location, self.inner.location],
3087 if self.inner.isSequence():
3088 raise WebIDLError(
3089 "The inner type of an ObservableArray type must not "
3090 "be a sequence type",
3091 [self.location, self.inner.location],
3093 if self.inner.isRecord():
3094 raise WebIDLError(
3095 "The inner type of an ObservableArray type must not be a record type",
3096 [self.location, self.inner.location],
3098 if self.inner.isObservableArray():
3099 raise WebIDLError(
3100 "The inner type of an ObservableArray type must not "
3101 "be an ObservableArray type",
3102 [self.location, self.inner.location],
3105 self.name = self.inner.name + "ObservableArray"
3106 return self
3108 def isDistinguishableFrom(self, other):
3109 # ObservableArrays are not distinguishable from anything.
3110 return False
3113 class IDLUnionType(IDLType):
3114 def __init__(self, location, memberTypes):
3115 IDLType.__init__(self, location, "")
3116 self.memberTypes = memberTypes
3117 self.hasNullableType = False
3118 self._dictionaryType = None
3119 self.flatMemberTypes = None
3120 self.builtin = False
3122 def __eq__(self, other):
3123 return isinstance(other, IDLUnionType) and self.memberTypes == other.memberTypes
3125 def __hash__(self):
3126 assert self.isComplete()
3127 return self.name.__hash__()
3129 def prettyName(self):
3130 return "(" + " or ".join(m.prettyName() for m in self.memberTypes) + ")"
3132 def isUnion(self):
3133 return True
3135 def isJSONType(self):
3136 return all(m.isJSONType() for m in self.memberTypes)
3138 def includesRestrictedFloat(self):
3139 return any(t.includesRestrictedFloat() for t in self.memberTypes)
3141 def tag(self):
3142 return IDLType.Tags.union
3144 def resolveType(self, parentScope):
3145 assert isinstance(parentScope, IDLScope)
3146 for t in self.memberTypes:
3147 t.resolveType(parentScope)
3149 def isComplete(self):
3150 return self.flatMemberTypes is not None
3152 def complete(self, scope):
3153 def typeName(type):
3154 if isinstance(type, IDLNullableType):
3155 return typeName(type.inner) + "OrNull"
3156 if isinstance(type, IDLWrapperType):
3157 return typeName(type._identifier.object())
3158 if isinstance(type, IDLObjectWithIdentifier):
3159 return typeName(type.identifier)
3160 if isinstance(type, IDLBuiltinType) and type.hasAllowShared():
3161 assert type.isBufferSource()
3162 return "MaybeShared" + type.name
3163 return type.name
3165 for i, type in enumerate(self.memberTypes):
3166 if not type.isComplete():
3167 self.memberTypes[i] = type.complete(scope)
3169 self.name = "Or".join(typeName(type) for type in self.memberTypes)
3170 self.flatMemberTypes = list(self.memberTypes)
3171 i = 0
3172 while i < len(self.flatMemberTypes):
3173 if self.flatMemberTypes[i].nullable():
3174 if self.hasNullableType:
3175 raise WebIDLError(
3176 "Can't have more than one nullable types in a union",
3177 [nullableType.location, self.flatMemberTypes[i].location],
3179 if self.hasDictionaryType():
3180 raise WebIDLError(
3181 "Can't have a nullable type and a "
3182 "dictionary type in a union",
3184 self._dictionaryType.location,
3185 self.flatMemberTypes[i].location,
3188 self.hasNullableType = True
3189 nullableType = self.flatMemberTypes[i]
3190 self.flatMemberTypes[i] = self.flatMemberTypes[i].inner
3191 continue
3192 if self.flatMemberTypes[i].isDictionary():
3193 if self.hasNullableType:
3194 raise WebIDLError(
3195 "Can't have a nullable type and a "
3196 "dictionary type in a union",
3197 [nullableType.location, self.flatMemberTypes[i].location],
3199 self._dictionaryType = self.flatMemberTypes[i]
3200 self.flatMemberTypes[i].inner.needsConversionFromJS = True
3201 elif self.flatMemberTypes[i].isUnion():
3202 self.flatMemberTypes[i : i + 1] = self.flatMemberTypes[i].memberTypes
3203 continue
3204 i += 1
3206 for i, t in enumerate(self.flatMemberTypes[:-1]):
3207 for u in self.flatMemberTypes[i + 1 :]:
3208 if not t.isDistinguishableFrom(u):
3209 raise WebIDLError(
3210 "Flat member types of a union should be "
3211 "distinguishable, " + str(t) + " is not "
3212 "distinguishable from " + str(u),
3213 [self.location, t.location, u.location],
3216 return self
3218 def isDistinguishableFrom(self, other):
3219 if self.hasNullableType and other.nullable():
3220 # Can't tell which type null should become
3221 return False
3222 if other.isUnion():
3223 otherTypes = other.unroll().memberTypes
3224 else:
3225 otherTypes = [other]
3226 # For every type in otherTypes, check that it's distinguishable from
3227 # every type in our types
3228 for u in otherTypes:
3229 if any(not t.isDistinguishableFrom(u) for t in self.memberTypes):
3230 return False
3231 return True
3233 def isExposedInAllOf(self, exposureSet):
3234 # We could have different member types in different globals.
3235 # Just make sure that each thing in exposureSet has one of our member types exposed in it.
3236 for globalName in exposureSet:
3237 if not any(
3238 t.unroll().isExposedInAllOf(set([globalName]))
3239 for t in self.flatMemberTypes
3241 return False
3242 return True
3244 def hasDictionaryType(self):
3245 return self._dictionaryType is not None
3247 def hasPossiblyEmptyDictionaryType(self):
3248 return (
3249 self._dictionaryType is not None and self._dictionaryType.inner.canBeEmpty()
3252 def _getDependentObjects(self):
3253 return set(self.memberTypes)
3256 class IDLTypedefType(IDLType):
3257 def __init__(self, location, innerType, name):
3258 IDLType.__init__(self, location, name)
3259 self.inner = innerType
3260 self.builtin = False
3262 def __hash__(self):
3263 return hash(self.inner)
3265 def __eq__(self, other):
3266 return isinstance(other, IDLTypedefType) and self.inner == other.inner
3268 def __str__(self):
3269 return self.name
3271 def nullable(self):
3272 return self.inner.nullable()
3274 def isPrimitive(self):
3275 return self.inner.isPrimitive()
3277 def isBoolean(self):
3278 return self.inner.isBoolean()
3280 def isNumeric(self):
3281 return self.inner.isNumeric()
3283 def isString(self):
3284 return self.inner.isString()
3286 def isByteString(self):
3287 return self.inner.isByteString()
3289 def isDOMString(self):
3290 return self.inner.isDOMString()
3292 def isUSVString(self):
3293 return self.inner.isUSVString()
3295 def isUTF8String(self):
3296 return self.inner.isUTF8String()
3298 def isJSString(self):
3299 return self.inner.isJSString()
3301 def isUndefined(self):
3302 return self.inner.isUndefined()
3304 def isJSONType(self):
3305 return self.inner.isJSONType()
3307 def isSequence(self):
3308 return self.inner.isSequence()
3310 def isRecord(self):
3311 return self.inner.isRecord()
3313 def isDictionary(self):
3314 return self.inner.isDictionary()
3316 def isArrayBuffer(self):
3317 return self.inner.isArrayBuffer()
3319 def isArrayBufferView(self):
3320 return self.inner.isArrayBufferView()
3322 def isTypedArray(self):
3323 return self.inner.isTypedArray()
3325 def isInterface(self):
3326 return self.inner.isInterface()
3328 def isCallbackInterface(self):
3329 return self.inner.isCallbackInterface()
3331 def isNonCallbackInterface(self):
3332 return self.inner.isNonCallbackInterface()
3334 def isComplete(self):
3335 return False
3337 def complete(self, parentScope):
3338 if not self.inner.isComplete():
3339 self.inner = self.inner.complete(parentScope)
3340 assert self.inner.isComplete()
3341 return self.inner
3343 # Do we need a resolveType impl? I don't think it's particularly useful....
3345 def tag(self):
3346 return self.inner.tag()
3348 def unroll(self):
3349 return self.inner.unroll()
3351 def isDistinguishableFrom(self, other):
3352 return self.inner.isDistinguishableFrom(other)
3354 def _getDependentObjects(self):
3355 return self.inner._getDependentObjects()
3357 def withExtendedAttributes(self, attrs):
3358 return IDLTypedefType(
3359 self.location, self.inner.withExtendedAttributes(attrs), self.name
3363 class IDLTypedef(IDLObjectWithIdentifier):
3364 def __init__(self, location, parentScope, innerType, name):
3365 # Set self.innerType first, because IDLObjectWithIdentifier.__init__
3366 # will call our __str__, which wants to use it.
3367 self.innerType = innerType
3368 identifier = IDLUnresolvedIdentifier(location, name)
3369 IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
3371 def __str__(self):
3372 return "Typedef %s %s" % (self.identifier.name, self.innerType)
3374 def finish(self, parentScope):
3375 if not self.innerType.isComplete():
3376 self.innerType = self.innerType.complete(parentScope)
3378 def validate(self):
3379 pass
3381 def isTypedef(self):
3382 return True
3384 def addExtendedAttributes(self, attrs):
3385 if len(attrs) != 0:
3386 raise WebIDLError(
3387 "There are no extended attributes that are " "allowed on typedefs",
3388 [attrs[0].location, self.location],
3391 def _getDependentObjects(self):
3392 return self.innerType._getDependentObjects()
3395 class IDLWrapperType(IDLType):
3396 def __init__(self, location, inner):
3397 IDLType.__init__(self, location, inner.identifier.name)
3398 self.inner = inner
3399 self._identifier = inner.identifier
3400 self.builtin = False
3402 def __hash__(self):
3403 return hash(self._identifier) + hash(self.builtin)
3405 def __eq__(self, other):
3406 return (
3407 isinstance(other, IDLWrapperType)
3408 and self._identifier == other._identifier
3409 and self.builtin == other.builtin
3412 def __str__(self):
3413 return str(self.name) + " (Wrapper)"
3415 def isDictionary(self):
3416 return isinstance(self.inner, IDLDictionary)
3418 def isInterface(self):
3419 return isinstance(self.inner, IDLInterface) or isinstance(
3420 self.inner, IDLExternalInterface
3423 def isCallbackInterface(self):
3424 return self.isInterface() and self.inner.isCallback()
3426 def isNonCallbackInterface(self):
3427 return self.isInterface() and not self.inner.isCallback()
3429 def isEnum(self):
3430 return isinstance(self.inner, IDLEnum)
3432 def isJSONType(self):
3433 if self.isInterface():
3434 if self.inner.isExternal():
3435 return False
3436 iface = self.inner
3437 while iface:
3438 if any(m.isMethod() and m.isToJSON() for m in iface.members):
3439 return True
3440 iface = iface.parent
3441 return False
3442 elif self.isEnum():
3443 return True
3444 elif self.isDictionary():
3445 dictionary = self.inner
3446 while dictionary:
3447 if not all(m.type.isJSONType() for m in dictionary.members):
3448 return False
3449 dictionary = dictionary.parent
3450 return True
3451 else:
3452 raise WebIDLError(
3453 "IDLWrapperType wraps type %s that we don't know if "
3454 "is serializable" % type(self.inner),
3455 [self.location],
3458 def resolveType(self, parentScope):
3459 assert isinstance(parentScope, IDLScope)
3460 self.inner.resolve(parentScope)
3462 def isComplete(self):
3463 return True
3465 def tag(self):
3466 if self.isInterface():
3467 return IDLType.Tags.interface
3468 elif self.isEnum():
3469 return IDLType.Tags.enum
3470 elif self.isDictionary():
3471 return IDLType.Tags.dictionary
3472 else:
3473 assert False
3475 def isDistinguishableFrom(self, other):
3476 if other.isPromise():
3477 return False
3478 if other.isUnion():
3479 # Just forward to the union; it'll deal
3480 return other.isDistinguishableFrom(self)
3481 assert self.isInterface() or self.isEnum() or self.isDictionary()
3482 if self.isEnum():
3483 return (
3484 other.isUndefined()
3485 or other.isPrimitive()
3486 or other.isInterface()
3487 or other.isObject()
3488 or other.isCallback()
3489 or other.isDictionary()
3490 or other.isSequence()
3491 or other.isRecord()
3493 if self.isDictionary() and (other.nullable() or other.isUndefined()):
3494 return False
3495 if (
3496 other.isPrimitive()
3497 or other.isString()
3498 or other.isEnum()
3499 or other.isSequence()
3501 return True
3502 if self.isDictionary():
3503 # Callbacks without `LegacyTreatNonObjectAsNull` are distinguishable from Dictionary likes
3504 if other.isCallback():
3505 return not other.callback._treatNonObjectAsNull
3506 return other.isNonCallbackInterface()
3508 assert self.isInterface()
3509 if other.isInterface():
3510 if other.isSpiderMonkeyInterface():
3511 # Just let |other| handle things
3512 return other.isDistinguishableFrom(self)
3513 assert self.isGeckoInterface() and other.isGeckoInterface()
3514 if self.inner.isExternal() or other.unroll().inner.isExternal():
3515 return self != other
3516 return len(
3517 self.inner.interfacesBasedOnSelf
3518 & other.unroll().inner.interfacesBasedOnSelf
3519 ) == 0 and (self.isNonCallbackInterface() or other.isNonCallbackInterface())
3520 if (
3521 other.isUndefined()
3522 or other.isDictionary()
3523 or other.isCallback()
3524 or other.isRecord()
3526 return self.isNonCallbackInterface()
3528 # Not much else |other| can be.
3529 # any is the union of all non-union types, so it's not distinguishable
3530 # from other unions (because it is a union itself), or from all
3531 # non-union types (because it has all of them as its members).
3532 assert other.isAny() or other.isObject()
3533 return False
3535 def isExposedInAllOf(self, exposureSet):
3536 if not self.isInterface():
3537 return True
3538 iface = self.inner
3539 if iface.isExternal():
3540 # Let's say true, so we don't have to implement exposure mixins on
3541 # external interfaces and sprinkle [Exposed=Window] on every single
3542 # external interface declaration.
3543 return True
3544 return iface.exposureSet.issuperset(exposureSet)
3546 def _getDependentObjects(self):
3547 # NB: The codegen for an interface type depends on
3548 # a) That the identifier is in fact an interface (as opposed to
3549 # a dictionary or something else).
3550 # b) The native type of the interface.
3551 # If we depend on the interface object we will also depend on
3552 # anything the interface depends on which is undesirable. We
3553 # considered implementing a dependency just on the interface type
3554 # file, but then every modification to an interface would cause this
3555 # to be regenerated which is still undesirable. We decided not to
3556 # depend on anything, reasoning that:
3557 # 1) Changing the concrete type of the interface requires modifying
3558 # Bindings.conf, which is still a global dependency.
3559 # 2) Changing an interface to a dictionary (or vice versa) with the
3560 # same identifier should be incredibly rare.
3562 # On the other hand, if our type is a dictionary, we should
3563 # depend on it, because the member types of a dictionary
3564 # affect whether a method taking the dictionary as an argument
3565 # takes a JSContext* argument or not.
3566 if self.isDictionary():
3567 return set([self.inner])
3568 return set()
3571 class IDLPromiseType(IDLParametrizedType):
3572 def __init__(self, location, innerType):
3573 IDLParametrizedType.__init__(self, location, "Promise", innerType)
3575 def __hash__(self):
3576 return hash(self.promiseInnerType())
3578 def __eq__(self, other):
3579 return (
3580 isinstance(other, IDLPromiseType)
3581 and self.promiseInnerType() == other.promiseInnerType()
3584 def __str__(self):
3585 return self.inner.__str__() + "Promise"
3587 def prettyName(self):
3588 return "Promise<%s>" % self.inner.prettyName()
3590 def isPromise(self):
3591 return True
3593 def promiseInnerType(self):
3594 return self.inner
3596 def tag(self):
3597 return IDLType.Tags.promise
3599 def complete(self, scope):
3600 if self.inner.isObservableArray():
3601 raise WebIDLError(
3602 "The inner type of a promise type must not be an ObservableArray type",
3603 [self.location, self.inner.location],
3606 self.inner = self.promiseInnerType().complete(scope)
3607 return self
3609 def unroll(self):
3610 # We do not unroll our inner. Just stop at ourselves. That
3611 # lets us add headers for both ourselves and our inner as
3612 # needed.
3613 return self
3615 def isDistinguishableFrom(self, other):
3616 # Promises are not distinguishable from anything.
3617 return False
3619 def isExposedInAllOf(self, exposureSet):
3620 # Check the internal type
3621 return self.promiseInnerType().unroll().isExposedInAllOf(exposureSet)
3624 class IDLBuiltinType(IDLType):
3625 Types = enum(
3626 # The integer types
3627 "byte",
3628 "octet",
3629 "short",
3630 "unsigned_short",
3631 "long",
3632 "unsigned_long",
3633 "long_long",
3634 "unsigned_long_long",
3635 # Additional primitive types
3636 "boolean",
3637 "unrestricted_float",
3638 "float",
3639 "unrestricted_double",
3640 # IMPORTANT: "double" must be the last primitive type listed
3641 "double",
3642 # Other types
3643 "any",
3644 "undefined",
3645 "domstring",
3646 "bytestring",
3647 "usvstring",
3648 "utf8string",
3649 "jsstring",
3650 "object",
3651 # Funny stuff
3652 "ArrayBuffer",
3653 "ArrayBufferView",
3654 "Int8Array",
3655 "Uint8Array",
3656 "Uint8ClampedArray",
3657 "Int16Array",
3658 "Uint16Array",
3659 "Int32Array",
3660 "Uint32Array",
3661 "Float32Array",
3662 "Float64Array",
3665 TagLookup = {
3666 Types.byte: IDLType.Tags.int8,
3667 Types.octet: IDLType.Tags.uint8,
3668 Types.short: IDLType.Tags.int16,
3669 Types.unsigned_short: IDLType.Tags.uint16,
3670 Types.long: IDLType.Tags.int32,
3671 Types.unsigned_long: IDLType.Tags.uint32,
3672 Types.long_long: IDLType.Tags.int64,
3673 Types.unsigned_long_long: IDLType.Tags.uint64,
3674 Types.boolean: IDLType.Tags.bool,
3675 Types.unrestricted_float: IDLType.Tags.unrestricted_float,
3676 Types.float: IDLType.Tags.float,
3677 Types.unrestricted_double: IDLType.Tags.unrestricted_double,
3678 Types.double: IDLType.Tags.double,
3679 Types.any: IDLType.Tags.any,
3680 Types.undefined: IDLType.Tags.undefined,
3681 Types.domstring: IDLType.Tags.domstring,
3682 Types.bytestring: IDLType.Tags.bytestring,
3683 Types.usvstring: IDLType.Tags.usvstring,
3684 Types.utf8string: IDLType.Tags.utf8string,
3685 Types.jsstring: IDLType.Tags.jsstring,
3686 Types.object: IDLType.Tags.object,
3687 Types.ArrayBuffer: IDLType.Tags.interface,
3688 Types.ArrayBufferView: IDLType.Tags.interface,
3689 Types.Int8Array: IDLType.Tags.interface,
3690 Types.Uint8Array: IDLType.Tags.interface,
3691 Types.Uint8ClampedArray: IDLType.Tags.interface,
3692 Types.Int16Array: IDLType.Tags.interface,
3693 Types.Uint16Array: IDLType.Tags.interface,
3694 Types.Int32Array: IDLType.Tags.interface,
3695 Types.Uint32Array: IDLType.Tags.interface,
3696 Types.Float32Array: IDLType.Tags.interface,
3697 Types.Float64Array: IDLType.Tags.interface,
3700 PrettyNames = {
3701 Types.byte: "byte",
3702 Types.octet: "octet",
3703 Types.short: "short",
3704 Types.unsigned_short: "unsigned short",
3705 Types.long: "long",
3706 Types.unsigned_long: "unsigned long",
3707 Types.long_long: "long long",
3708 Types.unsigned_long_long: "unsigned long long",
3709 Types.boolean: "boolean",
3710 Types.unrestricted_float: "unrestricted float",
3711 Types.float: "float",
3712 Types.unrestricted_double: "unrestricted double",
3713 Types.double: "double",
3714 Types.any: "any",
3715 Types.undefined: "undefined",
3716 Types.domstring: "DOMString",
3717 Types.bytestring: "ByteString",
3718 Types.usvstring: "USVString",
3719 Types.utf8string: "USVString", # That's what it is in spec terms
3720 Types.jsstring: "USVString", # Again, that's what it is in spec terms
3721 Types.object: "object",
3722 Types.ArrayBuffer: "ArrayBuffer",
3723 Types.ArrayBufferView: "ArrayBufferView",
3724 Types.Int8Array: "Int8Array",
3725 Types.Uint8Array: "Uint8Array",
3726 Types.Uint8ClampedArray: "Uint8ClampedArray",
3727 Types.Int16Array: "Int16Array",
3728 Types.Uint16Array: "Uint16Array",
3729 Types.Int32Array: "Int32Array",
3730 Types.Uint32Array: "Uint32Array",
3731 Types.Float32Array: "Float32Array",
3732 Types.Float64Array: "Float64Array",
3735 def __init__(
3736 self,
3737 location,
3738 name,
3739 type,
3740 clamp=False,
3741 enforceRange=False,
3742 legacyNullToEmptyString=False,
3743 allowShared=False,
3744 attrLocation=[],
3747 The mutually exclusive clamp/enforceRange/legacyNullToEmptyString/allowShared arguments
3748 are used to create instances of this type with the appropriate attributes attached. Use
3749 .clamped(), .rangeEnforced(), .withLegacyNullToEmptyString() and .withAllowShared().
3751 attrLocation is an array of source locations of these attributes for error reporting.
3753 IDLType.__init__(self, location, name)
3754 self.builtin = True
3755 self._typeTag = type
3756 self._clamped = None
3757 self._rangeEnforced = None
3758 self._withLegacyNullToEmptyString = None
3759 self._withAllowShared = None
3760 if self.isInteger():
3761 if clamp:
3762 self._clamp = True
3763 self.name = "Clamped" + self.name
3764 self._extendedAttrDict["Clamp"] = True
3765 elif enforceRange:
3766 self._enforceRange = True
3767 self.name = "RangeEnforced" + self.name
3768 self._extendedAttrDict["EnforceRange"] = True
3769 elif clamp or enforceRange:
3770 raise WebIDLError(
3771 "Non-integer types cannot be [Clamp] or [EnforceRange]", attrLocation
3773 if self.isDOMString() or self.isUTF8String():
3774 if legacyNullToEmptyString:
3775 self.legacyNullToEmptyString = True
3776 self.name = "NullIsEmpty" + self.name
3777 self._extendedAttrDict["LegacyNullToEmptyString"] = True
3778 elif legacyNullToEmptyString:
3779 raise WebIDLError(
3780 "Non-string types cannot be [LegacyNullToEmptyString]", attrLocation
3782 if self.isBufferSource():
3783 if allowShared:
3784 self._allowShared = True
3785 self._extendedAttrDict["AllowShared"] = True
3786 elif allowShared:
3787 raise WebIDLError(
3788 "Types that are not buffer source types cannot be [AllowShared]",
3789 attrLocation,
3792 def __str__(self):
3793 if self._allowShared:
3794 assert self.isBufferSource()
3795 return "MaybeShared" + str(self.name)
3796 return str(self.name)
3798 def prettyName(self):
3799 return IDLBuiltinType.PrettyNames[self._typeTag]
3801 def clamped(self, attrLocation):
3802 if not self._clamped:
3803 self._clamped = IDLBuiltinType(
3804 self.location,
3805 self.name,
3806 self._typeTag,
3807 clamp=True,
3808 attrLocation=attrLocation,
3810 return self._clamped
3812 def rangeEnforced(self, attrLocation):
3813 if not self._rangeEnforced:
3814 self._rangeEnforced = IDLBuiltinType(
3815 self.location,
3816 self.name,
3817 self._typeTag,
3818 enforceRange=True,
3819 attrLocation=attrLocation,
3821 return self._rangeEnforced
3823 def withLegacyNullToEmptyString(self, attrLocation):
3824 if not self._withLegacyNullToEmptyString:
3825 self._withLegacyNullToEmptyString = IDLBuiltinType(
3826 self.location,
3827 self.name,
3828 self._typeTag,
3829 legacyNullToEmptyString=True,
3830 attrLocation=attrLocation,
3832 return self._withLegacyNullToEmptyString
3834 def withAllowShared(self, attrLocation):
3835 if not self._withAllowShared:
3836 self._withAllowShared = IDLBuiltinType(
3837 self.location,
3838 self.name,
3839 self._typeTag,
3840 allowShared=True,
3841 attrLocation=attrLocation,
3843 return self._withAllowShared
3845 def isPrimitive(self):
3846 return self._typeTag <= IDLBuiltinType.Types.double
3848 def isBoolean(self):
3849 return self._typeTag == IDLBuiltinType.Types.boolean
3851 def isUndefined(self):
3852 return self._typeTag == IDLBuiltinType.Types.undefined
3854 def isNumeric(self):
3855 return self.isPrimitive() and not self.isBoolean()
3857 def isString(self):
3858 return (
3859 self._typeTag == IDLBuiltinType.Types.domstring
3860 or self._typeTag == IDLBuiltinType.Types.bytestring
3861 or self._typeTag == IDLBuiltinType.Types.usvstring
3862 or self._typeTag == IDLBuiltinType.Types.utf8string
3863 or self._typeTag == IDLBuiltinType.Types.jsstring
3866 def isByteString(self):
3867 return self._typeTag == IDLBuiltinType.Types.bytestring
3869 def isDOMString(self):
3870 return self._typeTag == IDLBuiltinType.Types.domstring
3872 def isUSVString(self):
3873 return self._typeTag == IDLBuiltinType.Types.usvstring
3875 def isUTF8String(self):
3876 return self._typeTag == IDLBuiltinType.Types.utf8string
3878 def isJSString(self):
3879 return self._typeTag == IDLBuiltinType.Types.jsstring
3881 def isInteger(self):
3882 return self._typeTag <= IDLBuiltinType.Types.unsigned_long_long
3884 def isArrayBuffer(self):
3885 return self._typeTag == IDLBuiltinType.Types.ArrayBuffer
3887 def isArrayBufferView(self):
3888 return self._typeTag == IDLBuiltinType.Types.ArrayBufferView
3890 def isTypedArray(self):
3891 return (
3892 self._typeTag >= IDLBuiltinType.Types.Int8Array
3893 and self._typeTag <= IDLBuiltinType.Types.Float64Array
3896 def isInterface(self):
3897 # TypedArray things are interface types per the TypedArray spec,
3898 # but we handle them as builtins because SpiderMonkey implements
3899 # all of it internally.
3900 return self.isArrayBuffer() or self.isArrayBufferView() or self.isTypedArray()
3902 def isNonCallbackInterface(self):
3903 # All the interfaces we can be are non-callback
3904 return self.isInterface()
3906 def isFloat(self):
3907 return (
3908 self._typeTag == IDLBuiltinType.Types.float
3909 or self._typeTag == IDLBuiltinType.Types.double
3910 or self._typeTag == IDLBuiltinType.Types.unrestricted_float
3911 or self._typeTag == IDLBuiltinType.Types.unrestricted_double
3914 def isUnrestricted(self):
3915 assert self.isFloat()
3916 return (
3917 self._typeTag == IDLBuiltinType.Types.unrestricted_float
3918 or self._typeTag == IDLBuiltinType.Types.unrestricted_double
3921 def isJSONType(self):
3922 return self.isPrimitive() or self.isString() or self.isObject()
3924 def includesRestrictedFloat(self):
3925 return self.isFloat() and not self.isUnrestricted()
3927 def tag(self):
3928 return IDLBuiltinType.TagLookup[self._typeTag]
3930 def isDistinguishableFrom(self, other):
3931 if other.isPromise():
3932 return False
3933 if other.isUnion():
3934 # Just forward to the union; it'll deal
3935 return other.isDistinguishableFrom(self)
3936 if self.isUndefined():
3937 return not (other.isUndefined() or other.isDictionaryLike())
3938 if self.isPrimitive():
3939 if (
3940 other.isUndefined()
3941 or other.isString()
3942 or other.isEnum()
3943 or other.isInterface()
3944 or other.isObject()
3945 or other.isCallback()
3946 or other.isDictionary()
3947 or other.isSequence()
3948 or other.isRecord()
3950 return True
3951 if self.isBoolean():
3952 return other.isNumeric()
3953 assert self.isNumeric()
3954 return other.isBoolean()
3955 if self.isString():
3956 return (
3957 other.isUndefined()
3958 or other.isPrimitive()
3959 or other.isInterface()
3960 or other.isObject()
3961 or other.isCallback()
3962 or other.isDictionary()
3963 or other.isSequence()
3964 or other.isRecord()
3966 if self.isAny():
3967 # Can't tell "any" apart from anything
3968 return False
3969 if self.isObject():
3970 return (
3971 other.isUndefined()
3972 or other.isPrimitive()
3973 or other.isString()
3974 or other.isEnum()
3976 # Not much else we could be!
3977 assert self.isSpiderMonkeyInterface()
3978 # Like interfaces, but we know we're not a callback
3979 return (
3980 other.isUndefined()
3981 or other.isPrimitive()
3982 or other.isString()
3983 or other.isEnum()
3984 or other.isCallback()
3985 or other.isDictionary()
3986 or other.isSequence()
3987 or other.isRecord()
3988 or (
3989 other.isInterface()
3990 and (
3991 # ArrayBuffer is distinguishable from everything
3992 # that's not an ArrayBuffer or a callback interface
3993 (self.isArrayBuffer() and not other.isArrayBuffer())
3995 # ArrayBufferView is distinguishable from everything
3996 # that's not an ArrayBufferView or typed array.
3998 self.isArrayBufferView()
3999 and not other.isArrayBufferView()
4000 and not other.isTypedArray()
4003 # Typed arrays are distinguishable from everything
4004 # except ArrayBufferView and the same type of typed
4005 # array
4007 self.isTypedArray()
4008 and not other.isArrayBufferView()
4009 and not (other.isTypedArray() and other.name == self.name)
4015 def _getDependentObjects(self):
4016 return set()
4018 def withExtendedAttributes(self, attrs):
4019 ret = self
4020 for attribute in attrs:
4021 identifier = attribute.identifier()
4022 if identifier == "Clamp":
4023 if not attribute.noArguments():
4024 raise WebIDLError(
4025 "[Clamp] must take no arguments", [attribute.location]
4027 if ret.hasEnforceRange() or self._enforceRange:
4028 raise WebIDLError(
4029 "[EnforceRange] and [Clamp] are mutually exclusive",
4030 [self.location, attribute.location],
4032 ret = self.clamped([self.location, attribute.location])
4033 elif identifier == "EnforceRange":
4034 if not attribute.noArguments():
4035 raise WebIDLError(
4036 "[EnforceRange] must take no arguments", [attribute.location]
4038 if ret.hasClamp() or self._clamp:
4039 raise WebIDLError(
4040 "[EnforceRange] and [Clamp] are mutually exclusive",
4041 [self.location, attribute.location],
4043 ret = self.rangeEnforced([self.location, attribute.location])
4044 elif identifier == "LegacyNullToEmptyString":
4045 if not (self.isDOMString() or self.isUTF8String()):
4046 raise WebIDLError(
4047 "[LegacyNullToEmptyString] only allowed on DOMStrings and UTF8Strings",
4048 [self.location, attribute.location],
4050 assert not self.nullable()
4051 if attribute.hasValue():
4052 raise WebIDLError(
4053 "[LegacyNullToEmptyString] must take no identifier argument",
4054 [attribute.location],
4056 ret = self.withLegacyNullToEmptyString(
4057 [self.location, attribute.location]
4059 elif identifier == "AllowShared":
4060 if not attribute.noArguments():
4061 raise WebIDLError(
4062 "[AllowShared] must take no arguments", [attribute.location]
4064 if not self.isBufferSource():
4065 raise WebIDLError(
4066 "[AllowShared] only allowed on buffer source types",
4067 [self.location, attribute.location],
4069 ret = self.withAllowShared([self.location, attribute.location])
4071 else:
4072 raise WebIDLError(
4073 "Unhandled extended attribute on type",
4074 [self.location, attribute.location],
4076 return ret
4079 BuiltinTypes = {
4080 IDLBuiltinType.Types.byte: IDLBuiltinType(
4081 BuiltinLocation("<builtin type>"), "Byte", IDLBuiltinType.Types.byte
4083 IDLBuiltinType.Types.octet: IDLBuiltinType(
4084 BuiltinLocation("<builtin type>"), "Octet", IDLBuiltinType.Types.octet
4086 IDLBuiltinType.Types.short: IDLBuiltinType(
4087 BuiltinLocation("<builtin type>"), "Short", IDLBuiltinType.Types.short
4089 IDLBuiltinType.Types.unsigned_short: IDLBuiltinType(
4090 BuiltinLocation("<builtin type>"),
4091 "UnsignedShort",
4092 IDLBuiltinType.Types.unsigned_short,
4094 IDLBuiltinType.Types.long: IDLBuiltinType(
4095 BuiltinLocation("<builtin type>"), "Long", IDLBuiltinType.Types.long
4097 IDLBuiltinType.Types.unsigned_long: IDLBuiltinType(
4098 BuiltinLocation("<builtin type>"),
4099 "UnsignedLong",
4100 IDLBuiltinType.Types.unsigned_long,
4102 IDLBuiltinType.Types.long_long: IDLBuiltinType(
4103 BuiltinLocation("<builtin type>"), "LongLong", IDLBuiltinType.Types.long_long
4105 IDLBuiltinType.Types.unsigned_long_long: IDLBuiltinType(
4106 BuiltinLocation("<builtin type>"),
4107 "UnsignedLongLong",
4108 IDLBuiltinType.Types.unsigned_long_long,
4110 IDLBuiltinType.Types.undefined: IDLBuiltinType(
4111 BuiltinLocation("<builtin type>"), "Undefined", IDLBuiltinType.Types.undefined
4113 IDLBuiltinType.Types.boolean: IDLBuiltinType(
4114 BuiltinLocation("<builtin type>"), "Boolean", IDLBuiltinType.Types.boolean
4116 IDLBuiltinType.Types.float: IDLBuiltinType(
4117 BuiltinLocation("<builtin type>"), "Float", IDLBuiltinType.Types.float
4119 IDLBuiltinType.Types.unrestricted_float: IDLBuiltinType(
4120 BuiltinLocation("<builtin type>"),
4121 "UnrestrictedFloat",
4122 IDLBuiltinType.Types.unrestricted_float,
4124 IDLBuiltinType.Types.double: IDLBuiltinType(
4125 BuiltinLocation("<builtin type>"), "Double", IDLBuiltinType.Types.double
4127 IDLBuiltinType.Types.unrestricted_double: IDLBuiltinType(
4128 BuiltinLocation("<builtin type>"),
4129 "UnrestrictedDouble",
4130 IDLBuiltinType.Types.unrestricted_double,
4132 IDLBuiltinType.Types.any: IDLBuiltinType(
4133 BuiltinLocation("<builtin type>"), "Any", IDLBuiltinType.Types.any
4135 IDLBuiltinType.Types.domstring: IDLBuiltinType(
4136 BuiltinLocation("<builtin type>"), "String", IDLBuiltinType.Types.domstring
4138 IDLBuiltinType.Types.bytestring: IDLBuiltinType(
4139 BuiltinLocation("<builtin type>"), "ByteString", IDLBuiltinType.Types.bytestring
4141 IDLBuiltinType.Types.usvstring: IDLBuiltinType(
4142 BuiltinLocation("<builtin type>"), "USVString", IDLBuiltinType.Types.usvstring
4144 IDLBuiltinType.Types.utf8string: IDLBuiltinType(
4145 BuiltinLocation("<builtin type>"), "UTF8String", IDLBuiltinType.Types.utf8string
4147 IDLBuiltinType.Types.jsstring: IDLBuiltinType(
4148 BuiltinLocation("<builtin type>"), "JSString", IDLBuiltinType.Types.jsstring
4150 IDLBuiltinType.Types.object: IDLBuiltinType(
4151 BuiltinLocation("<builtin type>"), "Object", IDLBuiltinType.Types.object
4153 IDLBuiltinType.Types.ArrayBuffer: IDLBuiltinType(
4154 BuiltinLocation("<builtin type>"),
4155 "ArrayBuffer",
4156 IDLBuiltinType.Types.ArrayBuffer,
4158 IDLBuiltinType.Types.ArrayBufferView: IDLBuiltinType(
4159 BuiltinLocation("<builtin type>"),
4160 "ArrayBufferView",
4161 IDLBuiltinType.Types.ArrayBufferView,
4163 IDLBuiltinType.Types.Int8Array: IDLBuiltinType(
4164 BuiltinLocation("<builtin type>"), "Int8Array", IDLBuiltinType.Types.Int8Array
4166 IDLBuiltinType.Types.Uint8Array: IDLBuiltinType(
4167 BuiltinLocation("<builtin type>"), "Uint8Array", IDLBuiltinType.Types.Uint8Array
4169 IDLBuiltinType.Types.Uint8ClampedArray: IDLBuiltinType(
4170 BuiltinLocation("<builtin type>"),
4171 "Uint8ClampedArray",
4172 IDLBuiltinType.Types.Uint8ClampedArray,
4174 IDLBuiltinType.Types.Int16Array: IDLBuiltinType(
4175 BuiltinLocation("<builtin type>"), "Int16Array", IDLBuiltinType.Types.Int16Array
4177 IDLBuiltinType.Types.Uint16Array: IDLBuiltinType(
4178 BuiltinLocation("<builtin type>"),
4179 "Uint16Array",
4180 IDLBuiltinType.Types.Uint16Array,
4182 IDLBuiltinType.Types.Int32Array: IDLBuiltinType(
4183 BuiltinLocation("<builtin type>"), "Int32Array", IDLBuiltinType.Types.Int32Array
4185 IDLBuiltinType.Types.Uint32Array: IDLBuiltinType(
4186 BuiltinLocation("<builtin type>"),
4187 "Uint32Array",
4188 IDLBuiltinType.Types.Uint32Array,
4190 IDLBuiltinType.Types.Float32Array: IDLBuiltinType(
4191 BuiltinLocation("<builtin type>"),
4192 "Float32Array",
4193 IDLBuiltinType.Types.Float32Array,
4195 IDLBuiltinType.Types.Float64Array: IDLBuiltinType(
4196 BuiltinLocation("<builtin type>"),
4197 "Float64Array",
4198 IDLBuiltinType.Types.Float64Array,
4203 integerTypeSizes = {
4204 IDLBuiltinType.Types.byte: (-128, 127),
4205 IDLBuiltinType.Types.octet: (0, 255),
4206 IDLBuiltinType.Types.short: (-32768, 32767),
4207 IDLBuiltinType.Types.unsigned_short: (0, 65535),
4208 IDLBuiltinType.Types.long: (-2147483648, 2147483647),
4209 IDLBuiltinType.Types.unsigned_long: (0, 4294967295),
4210 IDLBuiltinType.Types.long_long: (-9223372036854775808, 9223372036854775807),
4211 IDLBuiltinType.Types.unsigned_long_long: (0, 18446744073709551615),
4215 def matchIntegerValueToType(value):
4216 for type, extremes in integerTypeSizes.items():
4217 (min, max) = extremes
4218 if value <= max and value >= min:
4219 return BuiltinTypes[type]
4221 return None
4224 class NoCoercionFoundError(WebIDLError):
4226 A class we use to indicate generic coercion failures because none of the
4227 types worked out in IDLValue.coerceToType.
4231 class IDLValue(IDLObject):
4232 def __init__(self, location, type, value):
4233 IDLObject.__init__(self, location)
4234 self.type = type
4235 assert isinstance(type, IDLType)
4237 self.value = value
4239 def coerceToType(self, type, location):
4240 if type == self.type:
4241 return self # Nothing to do
4243 # We first check for unions to ensure that even if the union is nullable
4244 # we end up with the right flat member type, not the union's type.
4245 if type.isUnion():
4246 # We use the flat member types here, because if we have a nullable
4247 # member type, or a nested union, we want the type the value
4248 # actually coerces to, not the nullable or nested union type.
4249 for subtype in type.unroll().flatMemberTypes:
4250 try:
4251 coercedValue = self.coerceToType(subtype, location)
4252 # Create a new IDLValue to make sure that we have the
4253 # correct float/double type. This is necessary because we
4254 # use the value's type when it is a default value of a
4255 # union, and the union cares about the exact float type.
4256 return IDLValue(self.location, subtype, coercedValue.value)
4257 except Exception as e:
4258 # Make sure to propagate out WebIDLErrors that are not the
4259 # generic "hey, we could not coerce to this type at all"
4260 # exception, because those are specific "coercion failed for
4261 # reason X" exceptions. Note that we want to swallow
4262 # non-WebIDLErrors here, because those can just happen if
4263 # "type" is not something that can have a default value at
4264 # all.
4265 if isinstance(e, WebIDLError) and not isinstance(
4266 e, NoCoercionFoundError
4268 raise e
4270 # If the type allows null, rerun this matching on the inner type, except
4271 # nullable enums. We handle those specially, because we want our
4272 # default string values to stay strings even when assigned to a nullable
4273 # enum.
4274 elif type.nullable() and not type.isEnum():
4275 innerValue = self.coerceToType(type.inner, location)
4276 return IDLValue(self.location, type, innerValue.value)
4278 elif self.type.isInteger() and type.isInteger():
4279 # We're both integer types. See if we fit.
4281 (min, max) = integerTypeSizes[type._typeTag]
4282 if self.value <= max and self.value >= min:
4283 # Promote
4284 return IDLValue(self.location, type, self.value)
4285 else:
4286 raise WebIDLError(
4287 "Value %s is out of range for type %s." % (self.value, type),
4288 [location],
4290 elif self.type.isInteger() and type.isFloat():
4291 # Convert an integer literal into float
4292 if -(2**24) <= self.value <= 2**24:
4293 return IDLValue(self.location, type, float(self.value))
4294 else:
4295 raise WebIDLError(
4296 "Converting value %s to %s will lose precision."
4297 % (self.value, type),
4298 [location],
4300 elif self.type.isString() and type.isEnum():
4301 # Just keep our string, but make sure it's a valid value for this enum
4302 enum = type.unroll().inner
4303 if self.value not in enum.values():
4304 raise WebIDLError(
4305 "'%s' is not a valid default value for enum %s"
4306 % (self.value, enum.identifier.name),
4307 [location, enum.location],
4309 return self
4310 elif self.type.isFloat() and type.isFloat():
4311 if not type.isUnrestricted() and (
4312 self.value == float("inf")
4313 or self.value == float("-inf")
4314 or math.isnan(self.value)
4316 raise WebIDLError(
4317 "Trying to convert unrestricted value %s to non-unrestricted"
4318 % self.value,
4319 [location],
4321 return IDLValue(self.location, type, self.value)
4322 elif self.type.isString() and type.isUSVString():
4323 # Allow USVStrings to use default value just like
4324 # DOMString. No coercion is required in this case as Codegen.py
4325 # treats USVString just like DOMString, but with an
4326 # extra normalization step.
4327 assert self.type.isDOMString()
4328 return self
4329 elif self.type.isString() and (
4330 type.isByteString() or type.isJSString() or type.isUTF8String()
4332 # Allow ByteStrings, UTF8String, and JSStrings to use a default
4333 # value like DOMString.
4334 # No coercion is required as Codegen.py will handle the
4335 # extra steps. We want to make sure that our string contains
4336 # only valid characters, so we check that here.
4337 valid_ascii_lit = (
4338 " " + string.ascii_letters + string.digits + string.punctuation
4340 for idx, c in enumerate(self.value):
4341 if c not in valid_ascii_lit:
4342 raise WebIDLError(
4343 "Coercing this string literal %s to a ByteString is not supported yet. "
4344 "Coercion failed due to an unsupported byte %d at index %d."
4345 % (self.value.__repr__(), ord(c), idx),
4346 [location],
4349 return IDLValue(self.location, type, self.value)
4350 elif self.type.isDOMString() and type.legacyNullToEmptyString:
4351 # LegacyNullToEmptyString is a different type for resolution reasons,
4352 # however once you have a value it doesn't matter
4353 return self
4355 raise NoCoercionFoundError(
4356 "Cannot coerce type %s to type %s." % (self.type, type), [location]
4359 def _getDependentObjects(self):
4360 return set()
4363 class IDLNullValue(IDLObject):
4364 def __init__(self, location):
4365 IDLObject.__init__(self, location)
4366 self.type = None
4367 self.value = None
4369 def coerceToType(self, type, location):
4370 if (
4371 not isinstance(type, IDLNullableType)
4372 and not (type.isUnion() and type.hasNullableType)
4373 and not type.isAny()
4375 raise WebIDLError("Cannot coerce null value to type %s." % type, [location])
4377 nullValue = IDLNullValue(self.location)
4378 if type.isUnion() and not type.nullable() and type.hasDictionaryType():
4379 # We're actually a default value for the union's dictionary member.
4380 # Use its type.
4381 for t in type.flatMemberTypes:
4382 if t.isDictionary():
4383 nullValue.type = t
4384 return nullValue
4385 nullValue.type = type
4386 return nullValue
4388 def _getDependentObjects(self):
4389 return set()
4392 class IDLEmptySequenceValue(IDLObject):
4393 def __init__(self, location):
4394 IDLObject.__init__(self, location)
4395 self.type = None
4396 self.value = None
4398 def coerceToType(self, type, location):
4399 if type.isUnion():
4400 # We use the flat member types here, because if we have a nullable
4401 # member type, or a nested union, we want the type the value
4402 # actually coerces to, not the nullable or nested union type.
4403 for subtype in type.unroll().flatMemberTypes:
4404 try:
4405 return self.coerceToType(subtype, location)
4406 except Exception:
4407 pass
4409 if not type.isSequence():
4410 raise WebIDLError(
4411 "Cannot coerce empty sequence value to type %s." % type, [location]
4414 emptySequenceValue = IDLEmptySequenceValue(self.location)
4415 emptySequenceValue.type = type
4416 return emptySequenceValue
4418 def _getDependentObjects(self):
4419 return set()
4422 class IDLDefaultDictionaryValue(IDLObject):
4423 def __init__(self, location):
4424 IDLObject.__init__(self, location)
4425 self.type = None
4426 self.value = None
4428 def coerceToType(self, type, location):
4429 if type.isUnion():
4430 # We use the flat member types here, because if we have a nullable
4431 # member type, or a nested union, we want the type the value
4432 # actually coerces to, not the nullable or nested union type.
4433 for subtype in type.unroll().flatMemberTypes:
4434 try:
4435 return self.coerceToType(subtype, location)
4436 except Exception:
4437 pass
4439 if not type.isDictionary():
4440 raise WebIDLError(
4441 "Cannot coerce default dictionary value to type %s." % type, [location]
4444 defaultDictionaryValue = IDLDefaultDictionaryValue(self.location)
4445 defaultDictionaryValue.type = type
4446 return defaultDictionaryValue
4448 def _getDependentObjects(self):
4449 return set()
4452 class IDLUndefinedValue(IDLObject):
4453 def __init__(self, location):
4454 IDLObject.__init__(self, location)
4455 self.type = None
4456 self.value = None
4458 def coerceToType(self, type, location):
4459 if not type.isAny():
4460 raise WebIDLError(
4461 "Cannot coerce undefined value to type %s." % type, [location]
4464 undefinedValue = IDLUndefinedValue(self.location)
4465 undefinedValue.type = type
4466 return undefinedValue
4468 def _getDependentObjects(self):
4469 return set()
4472 class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
4473 Tags = enum(
4474 "Const", "Attr", "Method", "MaplikeOrSetlike", "AsyncIterable", "Iterable"
4477 Special = enum("Static", "Stringifier")
4479 AffectsValues = ("Nothing", "Everything")
4480 DependsOnValues = ("Nothing", "DOMState", "DeviceState", "Everything")
4482 def __init__(self, location, identifier, tag, extendedAttrDict=None):
4483 IDLObjectWithIdentifier.__init__(self, location, None, identifier)
4484 IDLExposureMixins.__init__(self, location)
4485 self.tag = tag
4486 if extendedAttrDict is None:
4487 self._extendedAttrDict = {}
4488 else:
4489 self._extendedAttrDict = extendedAttrDict
4491 def isMethod(self):
4492 return self.tag == IDLInterfaceMember.Tags.Method
4494 def isAttr(self):
4495 return self.tag == IDLInterfaceMember.Tags.Attr
4497 def isConst(self):
4498 return self.tag == IDLInterfaceMember.Tags.Const
4500 def isMaplikeOrSetlikeOrIterable(self):
4501 return (
4502 self.tag == IDLInterfaceMember.Tags.MaplikeOrSetlike
4503 or self.tag == IDLInterfaceMember.Tags.AsyncIterable
4504 or self.tag == IDLInterfaceMember.Tags.Iterable
4507 def isMaplikeOrSetlike(self):
4508 return self.tag == IDLInterfaceMember.Tags.MaplikeOrSetlike
4510 def addExtendedAttributes(self, attrs):
4511 for attr in attrs:
4512 self.handleExtendedAttribute(attr)
4513 attrlist = attr.listValue()
4514 self._extendedAttrDict[attr.identifier()] = (
4515 attrlist if len(attrlist) else True
4518 def handleExtendedAttribute(self, attr):
4519 pass
4521 def getExtendedAttribute(self, name):
4522 return self._extendedAttrDict.get(name, None)
4524 def finish(self, scope):
4525 IDLExposureMixins.finish(self, scope)
4527 def validate(self):
4528 if self.isAttr() or self.isMethod():
4529 if self.affects == "Everything" and self.dependsOn != "Everything":
4530 raise WebIDLError(
4531 "Interface member is flagged as affecting "
4532 "everything but not depending on everything. "
4533 "That seems rather unlikely.",
4534 [self.location],
4537 if self.getExtendedAttribute("NewObject"):
4538 if self.dependsOn == "Nothing" or self.dependsOn == "DOMState":
4539 raise WebIDLError(
4540 "A [NewObject] method is not idempotent, "
4541 "so it has to depend on something other than DOM state.",
4542 [self.location],
4544 if self.getExtendedAttribute("Cached") or self.getExtendedAttribute(
4545 "StoreInSlot"
4547 raise WebIDLError(
4548 "A [NewObject] attribute shouldnt be "
4549 "[Cached] or [StoreInSlot], since the point "
4550 "of those is to keep returning the same "
4551 "thing across multiple calls, which is not "
4552 "what [NewObject] does.",
4553 [self.location],
4556 def _setDependsOn(self, dependsOn):
4557 if self.dependsOn != "Everything":
4558 raise WebIDLError(
4559 "Trying to specify multiple different DependsOn, "
4560 "Pure, or Constant extended attributes for "
4561 "attribute",
4562 [self.location],
4564 if dependsOn not in IDLInterfaceMember.DependsOnValues:
4565 raise WebIDLError(
4566 "Invalid [DependsOn=%s] on attribute" % dependsOn, [self.location]
4568 self.dependsOn = dependsOn
4570 def _setAffects(self, affects):
4571 if self.affects != "Everything":
4572 raise WebIDLError(
4573 "Trying to specify multiple different Affects, "
4574 "Pure, or Constant extended attributes for "
4575 "attribute",
4576 [self.location],
4578 if affects not in IDLInterfaceMember.AffectsValues:
4579 raise WebIDLError(
4580 "Invalid [Affects=%s] on attribute" % affects, [self.location]
4582 self.affects = affects
4584 def _addAlias(self, alias):
4585 if alias in self.aliases:
4586 raise WebIDLError(
4587 "Duplicate [Alias=%s] on attribute" % alias, [self.location]
4589 self.aliases.append(alias)
4591 def _addBindingAlias(self, bindingAlias):
4592 if bindingAlias in self.bindingAliases:
4593 raise WebIDLError(
4594 "Duplicate [BindingAlias=%s] on attribute" % bindingAlias,
4595 [self.location],
4597 self.bindingAliases.append(bindingAlias)
4600 class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember):
4601 def __init__(self, location, identifier, ifaceType, keyType, valueType, ifaceKind):
4602 IDLInterfaceMember.__init__(self, location, identifier, ifaceKind)
4603 if keyType is not None:
4604 assert isinstance(keyType, IDLType)
4605 else:
4606 assert valueType is not None
4607 assert ifaceType in ["maplike", "setlike", "iterable", "asynciterable"]
4608 if valueType is not None:
4609 assert isinstance(valueType, IDLType)
4610 self.keyType = keyType
4611 self.valueType = valueType
4612 self.maplikeOrSetlikeOrIterableType = ifaceType
4613 self.disallowedMemberNames = []
4614 self.disallowedNonMethodNames = []
4616 def isMaplike(self):
4617 return self.maplikeOrSetlikeOrIterableType == "maplike"
4619 def isSetlike(self):
4620 return self.maplikeOrSetlikeOrIterableType == "setlike"
4622 def isIterable(self):
4623 return self.maplikeOrSetlikeOrIterableType == "iterable"
4625 def isAsyncIterable(self):
4626 return self.maplikeOrSetlikeOrIterableType == "asynciterable"
4628 def hasKeyType(self):
4629 return self.keyType is not None
4631 def hasValueType(self):
4632 return self.valueType is not None
4634 def checkCollisions(self, members, isAncestor):
4635 for member in members:
4636 # Check that there are no disallowed members
4637 if member.identifier.name in self.disallowedMemberNames and not (
4639 member.isMethod()
4640 and (
4641 member.isStatic() or member.isMaplikeOrSetlikeOrIterableMethod()
4644 or (member.isAttr() and member.isMaplikeOrSetlikeAttr())
4646 raise WebIDLError(
4647 "Member '%s' conflicts "
4648 "with reserved %s name."
4649 % (member.identifier.name, self.maplikeOrSetlikeOrIterableType),
4650 [self.location, member.location],
4652 # Check that there are no disallowed non-method members.
4653 # Ancestor members are always disallowed here; own members
4654 # are disallowed only if they're non-methods.
4655 if (
4656 isAncestor or member.isAttr() or member.isConst()
4657 ) and member.identifier.name in self.disallowedNonMethodNames:
4658 raise WebIDLError(
4659 "Member '%s' conflicts "
4660 "with reserved %s method."
4661 % (member.identifier.name, self.maplikeOrSetlikeOrIterableType),
4662 [self.location, member.location],
4665 def addMethod(
4666 self,
4667 name,
4668 members,
4669 allowExistingOperations,
4670 returnType,
4671 args=[],
4672 chromeOnly=False,
4673 isPure=False,
4674 affectsNothing=False,
4675 newObject=False,
4676 isIteratorAlias=False,
4679 Create an IDLMethod based on the parameters passed in.
4681 - members is the member list to add this function to, since this is
4682 called during the member expansion portion of interface object
4683 building.
4685 - chromeOnly is only True for read-only js implemented classes, to
4686 implement underscore prefixed convenience functions which would
4687 otherwise not be available, unlike the case of C++ bindings.
4689 - isPure is only True for idempotent functions, so it is not valid for
4690 things like keys, values, etc. that return a new object every time.
4692 - affectsNothing means that nothing changes due to this method, which
4693 affects JIT optimization behavior
4695 - newObject means the method creates and returns a new object.
4698 # Only add name to lists for collision checks if it's not chrome
4699 # only.
4700 if chromeOnly:
4701 name = "__" + name
4702 else:
4703 if not allowExistingOperations:
4704 self.disallowedMemberNames.append(name)
4705 else:
4706 self.disallowedNonMethodNames.append(name)
4707 # If allowExistingOperations is True, and another operation exists
4708 # with the same name as the one we're trying to add, don't add the
4709 # maplike/setlike operation.
4710 if allowExistingOperations:
4711 for m in members:
4712 if m.identifier.name == name and m.isMethod() and not m.isStatic():
4713 return
4714 method = IDLMethod(
4715 self.location,
4716 IDLUnresolvedIdentifier(
4717 self.location, name, allowDoubleUnderscore=chromeOnly
4719 returnType,
4720 args,
4721 maplikeOrSetlikeOrIterable=self,
4723 # We need to be able to throw from declaration methods
4724 method.addExtendedAttributes([IDLExtendedAttribute(self.location, ("Throws",))])
4725 if chromeOnly:
4726 method.addExtendedAttributes(
4727 [IDLExtendedAttribute(self.location, ("ChromeOnly",))]
4729 if isPure:
4730 method.addExtendedAttributes(
4731 [IDLExtendedAttribute(self.location, ("Pure",))]
4733 # Following attributes are used for keys/values/entries. Can't mark
4734 # them pure, since they return a new object each time they are run.
4735 if affectsNothing:
4736 method.addExtendedAttributes(
4738 IDLExtendedAttribute(self.location, ("DependsOn", "Everything")),
4739 IDLExtendedAttribute(self.location, ("Affects", "Nothing")),
4742 if newObject:
4743 method.addExtendedAttributes(
4744 [IDLExtendedAttribute(self.location, ("NewObject",))]
4746 if isIteratorAlias:
4747 if not self.isAsyncIterable():
4748 method.addExtendedAttributes(
4749 [IDLExtendedAttribute(self.location, ("Alias", "@@iterator"))]
4751 else:
4752 method.addExtendedAttributes(
4753 [IDLExtendedAttribute(self.location, ("Alias", "@@asyncIterator"))]
4755 members.append(method)
4757 def resolve(self, parentScope):
4758 if self.keyType:
4759 self.keyType.resolveType(parentScope)
4760 if self.valueType:
4761 self.valueType.resolveType(parentScope)
4763 def finish(self, scope):
4764 IDLInterfaceMember.finish(self, scope)
4765 if self.keyType and not self.keyType.isComplete():
4766 t = self.keyType.complete(scope)
4768 assert not isinstance(t, IDLUnresolvedType)
4769 assert not isinstance(t, IDLTypedefType)
4770 assert not isinstance(t.name, IDLUnresolvedIdentifier)
4771 self.keyType = t
4772 if self.valueType and not self.valueType.isComplete():
4773 t = self.valueType.complete(scope)
4775 assert not isinstance(t, IDLUnresolvedType)
4776 assert not isinstance(t, IDLTypedefType)
4777 assert not isinstance(t.name, IDLUnresolvedIdentifier)
4778 self.valueType = t
4780 def validate(self):
4781 IDLInterfaceMember.validate(self)
4783 def handleExtendedAttribute(self, attr):
4784 IDLInterfaceMember.handleExtendedAttribute(self, attr)
4786 def _getDependentObjects(self):
4787 deps = set()
4788 if self.keyType:
4789 deps.add(self.keyType)
4790 if self.valueType:
4791 deps.add(self.valueType)
4792 return deps
4794 def getForEachArguments(self):
4795 return [
4796 IDLArgument(
4797 self.location,
4798 IDLUnresolvedIdentifier(
4799 BuiltinLocation("<auto-generated-identifier>"), "callback"
4801 BuiltinTypes[IDLBuiltinType.Types.object],
4803 IDLArgument(
4804 self.location,
4805 IDLUnresolvedIdentifier(
4806 BuiltinLocation("<auto-generated-identifier>"), "thisArg"
4808 BuiltinTypes[IDLBuiltinType.Types.any],
4809 optional=True,
4814 # Iterable adds ES6 iterator style functions and traits
4815 # (keys/values/entries/@@iterator) to an interface.
4816 class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase):
4817 def __init__(self, location, identifier, keyType, valueType, scope):
4818 IDLMaplikeOrSetlikeOrIterableBase.__init__(
4819 self,
4820 location,
4821 identifier,
4822 "iterable",
4823 keyType,
4824 valueType,
4825 IDLInterfaceMember.Tags.Iterable,
4827 self.iteratorType = None
4829 def __str__(self):
4830 return "declared iterable with key '%s' and value '%s'" % (
4831 self.keyType,
4832 self.valueType,
4835 def expand(self, members):
4837 In order to take advantage of all of the method machinery in Codegen,
4838 we generate our functions as if they were part of the interface
4839 specification during parsing.
4841 # We only need to add entries/keys/values here if we're a pair iterator.
4842 # Value iterators just copy these from %ArrayPrototype% instead.
4843 if not self.isPairIterator():
4844 return
4846 # object entries()
4847 self.addMethod(
4848 "entries",
4849 members,
4850 False,
4851 self.iteratorType,
4852 affectsNothing=True,
4853 newObject=True,
4854 isIteratorAlias=True,
4856 # object keys()
4857 self.addMethod(
4858 "keys",
4859 members,
4860 False,
4861 self.iteratorType,
4862 affectsNothing=True,
4863 newObject=True,
4865 # object values()
4866 self.addMethod(
4867 "values",
4868 members,
4869 False,
4870 self.iteratorType,
4871 affectsNothing=True,
4872 newObject=True,
4875 # undefined forEach(callback(valueType, keyType), optional any thisArg)
4876 self.addMethod(
4877 "forEach",
4878 members,
4879 False,
4880 BuiltinTypes[IDLBuiltinType.Types.undefined],
4881 self.getForEachArguments(),
4884 def isValueIterator(self):
4885 return not self.isPairIterator()
4887 def isPairIterator(self):
4888 return self.hasKeyType()
4891 class IDLAsyncIterable(IDLMaplikeOrSetlikeOrIterableBase):
4892 def __init__(self, location, identifier, keyType, valueType, argList, scope):
4893 for arg in argList:
4894 if not arg.optional:
4895 raise WebIDLError(
4896 "The arguments of the asynchronously iterable declaration on "
4897 "%s must all be optional arguments." % identifier,
4898 [arg.location],
4901 IDLMaplikeOrSetlikeOrIterableBase.__init__(
4902 self,
4903 location,
4904 identifier,
4905 "asynciterable",
4906 keyType,
4907 valueType,
4908 IDLInterfaceMember.Tags.AsyncIterable,
4910 self.iteratorType = None
4911 self.argList = argList
4913 def __str__(self):
4914 return "declared async iterable with key '%s' and value '%s'" % (
4915 self.keyType,
4916 self.valueType,
4919 def expand(self, members):
4921 In order to take advantage of all of the method machinery in Codegen,
4922 we generate our functions as if they were part of the interface
4923 specification during parsing.
4925 # object values()
4926 self.addMethod(
4927 "values",
4928 members,
4929 False,
4930 self.iteratorType,
4931 self.argList,
4932 affectsNothing=True,
4933 newObject=True,
4934 isIteratorAlias=(not self.isPairIterator()),
4937 # We only need to add entries/keys here if we're a pair iterator.
4938 if not self.isPairIterator():
4939 return
4941 # Methods can't share their IDLArguments, so we need to make copies here.
4942 def copyArgList(argList):
4943 return map(copy.copy, argList)
4945 # object entries()
4946 self.addMethod(
4947 "entries",
4948 members,
4949 False,
4950 self.iteratorType,
4951 copyArgList(self.argList),
4952 affectsNothing=True,
4953 newObject=True,
4954 isIteratorAlias=True,
4956 # object keys()
4957 self.addMethod(
4958 "keys",
4959 members,
4960 False,
4961 self.iteratorType,
4962 copyArgList(self.argList),
4963 affectsNothing=True,
4964 newObject=True,
4967 def isValueIterator(self):
4968 return not self.isPairIterator()
4970 def isPairIterator(self):
4971 return self.hasKeyType()
4974 # MaplikeOrSetlike adds ES6 map-or-set-like traits to an interface.
4975 class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase):
4976 def __init__(
4977 self, location, identifier, maplikeOrSetlikeType, readonly, keyType, valueType
4979 IDLMaplikeOrSetlikeOrIterableBase.__init__(
4980 self,
4981 location,
4982 identifier,
4983 maplikeOrSetlikeType,
4984 keyType,
4985 valueType,
4986 IDLInterfaceMember.Tags.MaplikeOrSetlike,
4988 self.readonly = readonly
4989 self.slotIndices = None
4991 # When generating JSAPI access code, we need to know the backing object
4992 # type prefix to create the correct function. Generate here for reuse.
4993 if self.isMaplike():
4994 self.prefix = "Map"
4995 elif self.isSetlike():
4996 self.prefix = "Set"
4998 def __str__(self):
4999 return "declared '%s' with key '%s'" % (
5000 self.maplikeOrSetlikeOrIterableType,
5001 self.keyType,
5004 def expand(self, members):
5006 In order to take advantage of all of the method machinery in Codegen,
5007 we generate our functions as if they were part of the interface
5008 specification during parsing.
5010 # Both maplike and setlike have a size attribute
5011 members.append(
5012 IDLAttribute(
5013 self.location,
5014 IDLUnresolvedIdentifier(
5015 BuiltinLocation("<auto-generated-identifier>"), "size"
5017 BuiltinTypes[IDLBuiltinType.Types.unsigned_long],
5018 True,
5019 maplikeOrSetlike=self,
5022 self.reserved_ro_names = ["size"]
5023 self.disallowedMemberNames.append("size")
5025 # object entries()
5026 self.addMethod(
5027 "entries",
5028 members,
5029 False,
5030 BuiltinTypes[IDLBuiltinType.Types.object],
5031 affectsNothing=True,
5032 isIteratorAlias=self.isMaplike(),
5034 # object keys()
5035 self.addMethod(
5036 "keys",
5037 members,
5038 False,
5039 BuiltinTypes[IDLBuiltinType.Types.object],
5040 affectsNothing=True,
5042 # object values()
5043 self.addMethod(
5044 "values",
5045 members,
5046 False,
5047 BuiltinTypes[IDLBuiltinType.Types.object],
5048 affectsNothing=True,
5049 isIteratorAlias=self.isSetlike(),
5052 # undefined forEach(callback(valueType, keyType), thisVal)
5053 self.addMethod(
5054 "forEach",
5055 members,
5056 False,
5057 BuiltinTypes[IDLBuiltinType.Types.undefined],
5058 self.getForEachArguments(),
5061 def getKeyArg():
5062 return IDLArgument(
5063 self.location,
5064 IDLUnresolvedIdentifier(self.location, "key"),
5065 self.keyType,
5068 # boolean has(keyType key)
5069 self.addMethod(
5070 "has",
5071 members,
5072 False,
5073 BuiltinTypes[IDLBuiltinType.Types.boolean],
5074 [getKeyArg()],
5075 isPure=True,
5078 if not self.readonly:
5079 # undefined clear()
5080 self.addMethod(
5081 "clear", members, True, BuiltinTypes[IDLBuiltinType.Types.undefined], []
5083 # boolean delete(keyType key)
5084 self.addMethod(
5085 "delete",
5086 members,
5087 True,
5088 BuiltinTypes[IDLBuiltinType.Types.boolean],
5089 [getKeyArg()],
5092 if self.isSetlike():
5093 if not self.readonly:
5094 # Add returns the set object it just added to.
5095 # object add(keyType key)
5097 self.addMethod(
5098 "add",
5099 members,
5100 True,
5101 BuiltinTypes[IDLBuiltinType.Types.object],
5102 [getKeyArg()],
5104 return
5106 # If we get this far, we're a maplike declaration.
5108 # valueType get(keyType key)
5110 # Note that instead of the value type, we're using any here. The
5111 # validity checks should happen as things are inserted into the map,
5112 # and using any as the return type makes code generation much simpler.
5114 # TODO: Bug 1155340 may change this to use specific type to provide
5115 # more info to JIT.
5116 self.addMethod(
5117 "get",
5118 members,
5119 False,
5120 BuiltinTypes[IDLBuiltinType.Types.any],
5121 [getKeyArg()],
5122 isPure=True,
5125 def getValueArg():
5126 return IDLArgument(
5127 self.location,
5128 IDLUnresolvedIdentifier(self.location, "value"),
5129 self.valueType,
5132 if not self.readonly:
5133 self.addMethod(
5134 "set",
5135 members,
5136 True,
5137 BuiltinTypes[IDLBuiltinType.Types.object],
5138 [getKeyArg(), getValueArg()],
5142 class IDLConst(IDLInterfaceMember):
5143 def __init__(self, location, identifier, type, value):
5144 IDLInterfaceMember.__init__(
5145 self, location, identifier, IDLInterfaceMember.Tags.Const
5148 assert isinstance(type, IDLType)
5149 if type.isDictionary():
5150 raise WebIDLError(
5151 "A constant cannot be of a dictionary type", [self.location]
5153 if type.isRecord():
5154 raise WebIDLError("A constant cannot be of a record type", [self.location])
5155 self.type = type
5156 self.value = value
5158 if identifier.name == "prototype":
5159 raise WebIDLError(
5160 "The identifier of a constant must not be 'prototype'", [location]
5163 def __str__(self):
5164 return "'%s' const '%s'" % (self.type, self.identifier)
5166 def finish(self, scope):
5167 IDLInterfaceMember.finish(self, scope)
5169 if not self.type.isComplete():
5170 type = self.type.complete(scope)
5171 if not type.isPrimitive() and not type.isString():
5172 locations = [self.type.location, type.location]
5173 try:
5174 locations.append(type.inner.location)
5175 except Exception:
5176 pass
5177 raise WebIDLError("Incorrect type for constant", locations)
5178 self.type = type
5180 # The value might not match the type
5181 coercedValue = self.value.coerceToType(self.type, self.location)
5182 assert coercedValue
5184 self.value = coercedValue
5186 def validate(self):
5187 IDLInterfaceMember.validate(self)
5189 def handleExtendedAttribute(self, attr):
5190 identifier = attr.identifier()
5191 if identifier == "Exposed":
5192 convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
5193 elif (
5194 identifier == "Pref"
5195 or identifier == "ChromeOnly"
5196 or identifier == "Func"
5197 or identifier == "Trial"
5198 or identifier == "SecureContext"
5199 or identifier == "NonEnumerable"
5201 # Known attributes that we don't need to do anything with here
5202 pass
5203 else:
5204 raise WebIDLError(
5205 "Unknown extended attribute %s on constant" % identifier,
5206 [attr.location],
5208 IDLInterfaceMember.handleExtendedAttribute(self, attr)
5210 def _getDependentObjects(self):
5211 return set([self.type, self.value])
5214 class IDLAttribute(IDLInterfaceMember):
5215 def __init__(
5216 self,
5217 location,
5218 identifier,
5219 type,
5220 readonly,
5221 inherit=False,
5222 static=False,
5223 stringifier=False,
5224 maplikeOrSetlike=None,
5225 extendedAttrDict=None,
5227 IDLInterfaceMember.__init__(
5228 self,
5229 location,
5230 identifier,
5231 IDLInterfaceMember.Tags.Attr,
5232 extendedAttrDict=extendedAttrDict,
5235 assert isinstance(type, IDLType)
5236 self.type = type
5237 self.readonly = readonly
5238 self.inherit = inherit
5239 self._static = static
5240 self.legacyLenientThis = False
5241 self._legacyUnforgeable = False
5242 self.stringifier = stringifier
5243 self.slotIndices = None
5244 assert maplikeOrSetlike is None or isinstance(
5245 maplikeOrSetlike, IDLMaplikeOrSetlike
5247 self.maplikeOrSetlike = maplikeOrSetlike
5248 self.dependsOn = "Everything"
5249 self.affects = "Everything"
5250 self.bindingAliases = []
5252 if static and identifier.name == "prototype":
5253 raise WebIDLError(
5254 "The identifier of a static attribute must not be 'prototype'",
5255 [location],
5258 if readonly and inherit:
5259 raise WebIDLError(
5260 "An attribute cannot be both 'readonly' and 'inherit'", [self.location]
5263 def isStatic(self):
5264 return self._static
5266 def forceStatic(self):
5267 self._static = True
5269 def __str__(self):
5270 return "'%s' attribute '%s'" % (self.type, self.identifier)
5272 def finish(self, scope):
5273 IDLInterfaceMember.finish(self, scope)
5275 if not self.type.isComplete():
5276 t = self.type.complete(scope)
5278 assert not isinstance(t, IDLUnresolvedType)
5279 assert not isinstance(t, IDLTypedefType)
5280 assert not isinstance(t.name, IDLUnresolvedIdentifier)
5281 self.type = t
5283 if self.readonly and (
5284 self.type.hasClamp()
5285 or self.type.hasEnforceRange()
5286 or self.type.hasAllowShared()
5287 or self.type.legacyNullToEmptyString
5289 raise WebIDLError(
5290 "A readonly attribute cannot be [Clamp] or [EnforceRange] or [AllowShared]",
5291 [self.location],
5293 if self.type.isDictionary() and not self.getExtendedAttribute("Cached"):
5294 raise WebIDLError(
5295 "An attribute cannot be of a dictionary type", [self.location]
5297 if self.type.isSequence() and not self.getExtendedAttribute("Cached"):
5298 raise WebIDLError(
5299 "A non-cached attribute cannot be of a sequence " "type",
5300 [self.location],
5302 if self.type.isRecord() and not self.getExtendedAttribute("Cached"):
5303 raise WebIDLError(
5304 "A non-cached attribute cannot be of a record " "type", [self.location]
5306 if self.type.isUnion():
5307 for f in self.type.unroll().flatMemberTypes:
5308 if f.isDictionary():
5309 raise WebIDLError(
5310 "An attribute cannot be of a union "
5311 "type if one of its member types (or "
5312 "one of its member types's member "
5313 "types, and so on) is a dictionary "
5314 "type",
5315 [self.location, f.location],
5317 if f.isSequence():
5318 raise WebIDLError(
5319 "An attribute cannot be of a union "
5320 "type if one of its member types (or "
5321 "one of its member types's member "
5322 "types, and so on) is a sequence "
5323 "type",
5324 [self.location, f.location],
5326 if f.isRecord():
5327 raise WebIDLError(
5328 "An attribute cannot be of a union "
5329 "type if one of its member types (or "
5330 "one of its member types's member "
5331 "types, and so on) is a record "
5332 "type",
5333 [self.location, f.location],
5335 if not self.type.isInterface() and self.getExtendedAttribute("PutForwards"):
5336 raise WebIDLError(
5337 "An attribute with [PutForwards] must have an "
5338 "interface type as its type",
5339 [self.location],
5342 if not self.type.isInterface() and self.getExtendedAttribute("SameObject"):
5343 raise WebIDLError(
5344 "An attribute with [SameObject] must have an "
5345 "interface type as its type",
5346 [self.location],
5349 if self.type.isPromise() and not self.readonly:
5350 raise WebIDLError(
5351 "Promise-returning attributes must be readonly", [self.location]
5354 if self.type.isObservableArray():
5355 if self.isStatic():
5356 raise WebIDLError(
5357 "A static attribute cannot have an ObservableArray type",
5358 [self.location],
5360 if self.getExtendedAttribute("Cached") or self.getExtendedAttribute(
5361 "StoreInSlot"
5363 raise WebIDLError(
5364 "[Cached] and [StoreInSlot] must not be used "
5365 "on an attribute whose type is ObservableArray",
5366 [self.location],
5369 def validate(self):
5370 def typeContainsChromeOnlyDictionaryMember(type):
5371 if type.nullable() or type.isSequence() or type.isRecord():
5372 return typeContainsChromeOnlyDictionaryMember(type.inner)
5374 if type.isUnion():
5375 for memberType in type.flatMemberTypes:
5376 (contains, location) = typeContainsChromeOnlyDictionaryMember(
5377 memberType
5379 if contains:
5380 return (True, location)
5382 if type.isDictionary():
5383 dictionary = type.inner
5384 while dictionary:
5385 (contains, location) = dictionaryContainsChromeOnlyMember(
5386 dictionary
5388 if contains:
5389 return (True, location)
5390 dictionary = dictionary.parent
5392 return (False, None)
5394 def dictionaryContainsChromeOnlyMember(dictionary):
5395 for member in dictionary.members:
5396 if member.getExtendedAttribute("ChromeOnly"):
5397 return (True, member.location)
5398 (contains, location) = typeContainsChromeOnlyDictionaryMember(
5399 member.type
5401 if contains:
5402 return (True, location)
5403 return (False, None)
5405 IDLInterfaceMember.validate(self)
5407 if self.getExtendedAttribute("Cached") or self.getExtendedAttribute(
5408 "StoreInSlot"
5410 if not self.affects == "Nothing":
5411 raise WebIDLError(
5412 "Cached attributes and attributes stored in "
5413 "slots must be Constant or Pure or "
5414 "Affects=Nothing, since the getter won't always "
5415 "be called.",
5416 [self.location],
5418 (contains, location) = typeContainsChromeOnlyDictionaryMember(self.type)
5419 if contains:
5420 raise WebIDLError(
5421 "[Cached] and [StoreInSlot] must not be used "
5422 "on an attribute whose type contains a "
5423 "[ChromeOnly] dictionary member",
5424 [self.location, location],
5426 if self.getExtendedAttribute("Frozen"):
5427 if (
5428 not self.type.isSequence()
5429 and not self.type.isDictionary()
5430 and not self.type.isRecord()
5432 raise WebIDLError(
5433 "[Frozen] is only allowed on "
5434 "sequence-valued, dictionary-valued, and "
5435 "record-valued attributes",
5436 [self.location],
5438 if not self.type.unroll().isExposedInAllOf(self.exposureSet):
5439 raise WebIDLError(
5440 "Attribute returns a type that is not exposed "
5441 "everywhere where the attribute is exposed",
5442 [self.location],
5444 if self.getExtendedAttribute("CEReactions"):
5445 if self.readonly:
5446 raise WebIDLError(
5447 "[CEReactions] is not allowed on " "readonly attributes",
5448 [self.location],
5451 def handleExtendedAttribute(self, attr):
5452 identifier = attr.identifier()
5453 if (
5454 identifier == "SetterThrows"
5455 or identifier == "SetterCanOOM"
5456 or identifier == "SetterNeedsSubjectPrincipal"
5457 ) and self.readonly:
5458 raise WebIDLError(
5459 "Readonly attributes must not be flagged as " "[%s]" % identifier,
5460 [self.location],
5462 elif identifier == "BindingAlias":
5463 if not attr.hasValue():
5464 raise WebIDLError(
5465 "[BindingAlias] takes an identifier or string", [attr.location]
5467 self._addBindingAlias(attr.value())
5468 elif (
5470 identifier == "Throws"
5471 or identifier == "GetterThrows"
5472 or identifier == "CanOOM"
5473 or identifier == "GetterCanOOM"
5475 and self.getExtendedAttribute("StoreInSlot")
5476 ) or (
5477 identifier == "StoreInSlot"
5478 and (
5479 self.getExtendedAttribute("Throws")
5480 or self.getExtendedAttribute("GetterThrows")
5481 or self.getExtendedAttribute("CanOOM")
5482 or self.getExtendedAttribute("GetterCanOOM")
5485 raise WebIDLError("Throwing things can't be [StoreInSlot]", [attr.location])
5486 elif identifier == "LegacyLenientThis":
5487 if not attr.noArguments():
5488 raise WebIDLError(
5489 "[LegacyLenientThis] must take no arguments", [attr.location]
5491 if self.isStatic():
5492 raise WebIDLError(
5493 "[LegacyLenientThis] is only allowed on non-static " "attributes",
5494 [attr.location, self.location],
5496 if self.getExtendedAttribute("CrossOriginReadable"):
5497 raise WebIDLError(
5498 "[LegacyLenientThis] is not allowed in combination "
5499 "with [CrossOriginReadable]",
5500 [attr.location, self.location],
5502 if self.getExtendedAttribute("CrossOriginWritable"):
5503 raise WebIDLError(
5504 "[LegacyLenientThis] is not allowed in combination "
5505 "with [CrossOriginWritable]",
5506 [attr.location, self.location],
5508 self.legacyLenientThis = True
5509 elif identifier == "LegacyUnforgeable":
5510 if self.isStatic():
5511 raise WebIDLError(
5512 "[LegacyUnforgeable] is only allowed on non-static " "attributes",
5513 [attr.location, self.location],
5515 self._legacyUnforgeable = True
5516 elif identifier == "SameObject" and not self.readonly:
5517 raise WebIDLError(
5518 "[SameObject] only allowed on readonly attributes",
5519 [attr.location, self.location],
5521 elif identifier == "Constant" and not self.readonly:
5522 raise WebIDLError(
5523 "[Constant] only allowed on readonly attributes",
5524 [attr.location, self.location],
5526 elif identifier == "PutForwards":
5527 if not self.readonly:
5528 raise WebIDLError(
5529 "[PutForwards] is only allowed on readonly " "attributes",
5530 [attr.location, self.location],
5532 if self.type.isPromise():
5533 raise WebIDLError(
5534 "[PutForwards] is not allowed on " "Promise-typed attributes",
5535 [attr.location, self.location],
5537 if self.isStatic():
5538 raise WebIDLError(
5539 "[PutForwards] is only allowed on non-static " "attributes",
5540 [attr.location, self.location],
5542 if self.getExtendedAttribute("Replaceable") is not None:
5543 raise WebIDLError(
5544 "[PutForwards] and [Replaceable] can't both "
5545 "appear on the same attribute",
5546 [attr.location, self.location],
5548 if not attr.hasValue():
5549 raise WebIDLError(
5550 "[PutForwards] takes an identifier", [attr.location, self.location]
5552 elif identifier == "Replaceable":
5553 if not attr.noArguments():
5554 raise WebIDLError(
5555 "[Replaceable] must take no arguments", [attr.location]
5557 if not self.readonly:
5558 raise WebIDLError(
5559 "[Replaceable] is only allowed on readonly " "attributes",
5560 [attr.location, self.location],
5562 if self.type.isPromise():
5563 raise WebIDLError(
5564 "[Replaceable] is not allowed on " "Promise-typed attributes",
5565 [attr.location, self.location],
5567 if self.isStatic():
5568 raise WebIDLError(
5569 "[Replaceable] is only allowed on non-static " "attributes",
5570 [attr.location, self.location],
5572 if self.getExtendedAttribute("PutForwards") is not None:
5573 raise WebIDLError(
5574 "[PutForwards] and [Replaceable] can't both "
5575 "appear on the same attribute",
5576 [attr.location, self.location],
5578 elif identifier == "LegacyLenientSetter":
5579 if not attr.noArguments():
5580 raise WebIDLError(
5581 "[LegacyLenientSetter] must take no arguments", [attr.location]
5583 if not self.readonly:
5584 raise WebIDLError(
5585 "[LegacyLenientSetter] is only allowed on readonly " "attributes",
5586 [attr.location, self.location],
5588 if self.type.isPromise():
5589 raise WebIDLError(
5590 "[LegacyLenientSetter] is not allowed on "
5591 "Promise-typed attributes",
5592 [attr.location, self.location],
5594 if self.isStatic():
5595 raise WebIDLError(
5596 "[LegacyLenientSetter] is only allowed on non-static " "attributes",
5597 [attr.location, self.location],
5599 if self.getExtendedAttribute("PutForwards") is not None:
5600 raise WebIDLError(
5601 "[LegacyLenientSetter] and [PutForwards] can't both "
5602 "appear on the same attribute",
5603 [attr.location, self.location],
5605 if self.getExtendedAttribute("Replaceable") is not None:
5606 raise WebIDLError(
5607 "[LegacyLenientSetter] and [Replaceable] can't both "
5608 "appear on the same attribute",
5609 [attr.location, self.location],
5611 elif identifier == "LenientFloat":
5612 if self.readonly:
5613 raise WebIDLError(
5614 "[LenientFloat] used on a readonly attribute",
5615 [attr.location, self.location],
5617 if not self.type.includesRestrictedFloat():
5618 raise WebIDLError(
5619 "[LenientFloat] used on an attribute with a "
5620 "non-restricted-float type",
5621 [attr.location, self.location],
5623 elif identifier == "StoreInSlot":
5624 if self.getExtendedAttribute("Cached"):
5625 raise WebIDLError(
5626 "[StoreInSlot] and [Cached] must not be "
5627 "specified on the same attribute",
5628 [attr.location, self.location],
5630 elif identifier == "Cached":
5631 if self.getExtendedAttribute("StoreInSlot"):
5632 raise WebIDLError(
5633 "[Cached] and [StoreInSlot] must not be "
5634 "specified on the same attribute",
5635 [attr.location, self.location],
5637 elif identifier == "CrossOriginReadable" or identifier == "CrossOriginWritable":
5638 if not attr.noArguments():
5639 raise WebIDLError(
5640 "[%s] must take no arguments" % identifier, [attr.location]
5642 if self.isStatic():
5643 raise WebIDLError(
5644 "[%s] is only allowed on non-static " "attributes" % identifier,
5645 [attr.location, self.location],
5647 if self.getExtendedAttribute("LegacyLenientThis"):
5648 raise WebIDLError(
5649 "[LegacyLenientThis] is not allowed in combination "
5650 "with [%s]" % identifier,
5651 [attr.location, self.location],
5653 elif identifier == "Exposed":
5654 convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
5655 elif identifier == "Pure":
5656 if not attr.noArguments():
5657 raise WebIDLError("[Pure] must take no arguments", [attr.location])
5658 self._setDependsOn("DOMState")
5659 self._setAffects("Nothing")
5660 elif identifier == "Constant" or identifier == "SameObject":
5661 if not attr.noArguments():
5662 raise WebIDLError(
5663 "[%s] must take no arguments" % identifier, [attr.location]
5665 self._setDependsOn("Nothing")
5666 self._setAffects("Nothing")
5667 elif identifier == "Affects":
5668 if not attr.hasValue():
5669 raise WebIDLError("[Affects] takes an identifier", [attr.location])
5670 self._setAffects(attr.value())
5671 elif identifier == "DependsOn":
5672 if not attr.hasValue():
5673 raise WebIDLError("[DependsOn] takes an identifier", [attr.location])
5674 if (
5675 attr.value() != "Everything"
5676 and attr.value() != "DOMState"
5677 and not self.readonly
5679 raise WebIDLError(
5680 "[DependsOn=%s] only allowed on "
5681 "readonly attributes" % attr.value(),
5682 [attr.location, self.location],
5684 self._setDependsOn(attr.value())
5685 elif identifier == "UseCounter":
5686 if self.stringifier:
5687 raise WebIDLError(
5688 "[UseCounter] must not be used on a " "stringifier attribute",
5689 [attr.location, self.location],
5691 elif identifier == "Unscopable":
5692 if not attr.noArguments():
5693 raise WebIDLError(
5694 "[Unscopable] must take no arguments", [attr.location]
5696 if self.isStatic():
5697 raise WebIDLError(
5698 "[Unscopable] is only allowed on non-static "
5699 "attributes and operations",
5700 [attr.location, self.location],
5702 elif identifier == "CEReactions":
5703 if not attr.noArguments():
5704 raise WebIDLError(
5705 "[CEReactions] must take no arguments", [attr.location]
5707 elif (
5708 identifier == "Pref"
5709 or identifier == "Deprecated"
5710 or identifier == "SetterThrows"
5711 or identifier == "Throws"
5712 or identifier == "GetterThrows"
5713 or identifier == "SetterCanOOM"
5714 or identifier == "CanOOM"
5715 or identifier == "GetterCanOOM"
5716 or identifier == "ChromeOnly"
5717 or identifier == "Func"
5718 or identifier == "Trial"
5719 or identifier == "SecureContext"
5720 or identifier == "Frozen"
5721 or identifier == "NewObject"
5722 or identifier == "NeedsSubjectPrincipal"
5723 or identifier == "SetterNeedsSubjectPrincipal"
5724 or identifier == "GetterNeedsSubjectPrincipal"
5725 or identifier == "NeedsCallerType"
5726 or identifier == "BinaryName"
5727 or identifier == "NonEnumerable"
5728 or identifier == "BindingTemplate"
5730 # Known attributes that we don't need to do anything with here
5731 pass
5732 else:
5733 raise WebIDLError(
5734 "Unknown extended attribute %s on attribute" % identifier,
5735 [attr.location],
5737 IDLInterfaceMember.handleExtendedAttribute(self, attr)
5739 def getExtendedAttributes(self):
5740 return self._extendedAttrDict
5742 def resolve(self, parentScope):
5743 assert isinstance(parentScope, IDLScope)
5744 self.type.resolveType(parentScope)
5745 IDLObjectWithIdentifier.resolve(self, parentScope)
5747 def hasLegacyLenientThis(self):
5748 return self.legacyLenientThis
5750 def isMaplikeOrSetlikeAttr(self):
5752 True if this attribute was generated from an interface with
5753 maplike/setlike (e.g. this is the size attribute for
5754 maplike/setlike)
5756 return self.maplikeOrSetlike is not None
5758 def isLegacyUnforgeable(self):
5759 return self._legacyUnforgeable
5761 def _getDependentObjects(self):
5762 return set([self.type])
5764 def expand(self, members):
5765 assert self.stringifier
5766 if (
5767 not self.type.isDOMString()
5768 and not self.type.isUSVString()
5769 and not self.type.isUTF8String()
5771 raise WebIDLError(
5772 "The type of a stringifer attribute must be "
5773 "either DOMString, USVString or UTF8String",
5774 [self.location],
5776 identifier = IDLUnresolvedIdentifier(
5777 self.location, "__stringifier", allowDoubleUnderscore=True
5779 method = IDLMethod(
5780 self.location,
5781 identifier,
5782 returnType=self.type,
5783 arguments=[],
5784 stringifier=True,
5785 underlyingAttr=self,
5787 allowedExtAttrs = ["Throws", "NeedsSubjectPrincipal", "Pure"]
5788 # Safe to ignore these as they are only meaningful for attributes
5789 attributeOnlyExtAttrs = [
5790 "CEReactions",
5791 "CrossOriginWritable",
5792 "SetterThrows",
5794 for key, value in self._extendedAttrDict.items():
5795 if key in allowedExtAttrs:
5796 if value is not True:
5797 raise WebIDLError(
5798 "[%s] with a value is currently "
5799 "unsupported in stringifier attributes, "
5800 "please file a bug to add support" % key,
5801 [self.location],
5803 method.addExtendedAttributes(
5804 [IDLExtendedAttribute(self.location, (key,))]
5806 elif key not in attributeOnlyExtAttrs:
5807 raise WebIDLError(
5808 "[%s] is currently unsupported in "
5809 "stringifier attributes, please file a bug "
5810 "to add support" % key,
5811 [self.location],
5813 members.append(method)
5816 class IDLArgument(IDLObjectWithIdentifier):
5817 def __init__(
5818 self,
5819 location,
5820 identifier,
5821 type,
5822 optional=False,
5823 defaultValue=None,
5824 variadic=False,
5825 dictionaryMember=False,
5826 allowTypeAttributes=False,
5828 IDLObjectWithIdentifier.__init__(self, location, None, identifier)
5830 assert isinstance(type, IDLType)
5831 self.type = type
5833 self.optional = optional
5834 self.defaultValue = defaultValue
5835 self.variadic = variadic
5836 self.dictionaryMember = dictionaryMember
5837 self._isComplete = False
5838 self._allowTreatNonCallableAsNull = False
5839 self._extendedAttrDict = {}
5840 self.allowTypeAttributes = allowTypeAttributes
5842 assert not variadic or optional
5843 assert not variadic or not defaultValue
5845 def addExtendedAttributes(self, attrs):
5846 for attribute in attrs:
5847 identifier = attribute.identifier()
5848 if self.allowTypeAttributes and (
5849 identifier == "EnforceRange"
5850 or identifier == "Clamp"
5851 or identifier == "LegacyNullToEmptyString"
5852 or identifier == "AllowShared"
5854 self.type = self.type.withExtendedAttributes([attribute])
5855 elif identifier == "TreatNonCallableAsNull":
5856 self._allowTreatNonCallableAsNull = True
5857 elif self.dictionaryMember and (
5858 identifier == "ChromeOnly"
5859 or identifier == "Func"
5860 or identifier == "Trial"
5861 or identifier == "Pref"
5863 if not self.optional:
5864 raise WebIDLError(
5865 "[%s] must not be used on a required "
5866 "dictionary member" % identifier,
5867 [attribute.location],
5869 elif self.dictionaryMember and identifier == "BinaryType":
5870 if not len(attribute.listValue()) == 1:
5871 raise WebIDLError(
5872 "[%s] BinaryType must take one argument" % identifier,
5873 [attribute.location],
5875 if not self.defaultValue:
5876 raise WebIDLError(
5877 "[%s] BinaryType can't be used without default value"
5878 % identifier,
5879 [attribute.location],
5881 else:
5882 raise WebIDLError(
5883 "Unhandled extended attribute on %s"
5885 "a dictionary member"
5886 if self.dictionaryMember
5887 else "an argument"
5889 [attribute.location],
5891 attrlist = attribute.listValue()
5892 self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
5894 def getExtendedAttribute(self, name):
5895 return self._extendedAttrDict.get(name, None)
5897 def isComplete(self):
5898 return self._isComplete
5900 def complete(self, scope):
5901 if self._isComplete:
5902 return
5904 self._isComplete = True
5906 if not self.type.isComplete():
5907 type = self.type.complete(scope)
5908 assert not isinstance(type, IDLUnresolvedType)
5909 assert not isinstance(type, IDLTypedefType)
5910 assert not isinstance(type.name, IDLUnresolvedIdentifier)
5911 self.type = type
5913 if self.type.isUndefined():
5914 raise WebIDLError(
5915 "undefined must not be used as the type of an argument in any circumstance",
5916 [self.location],
5919 if self.type.isAny():
5920 assert self.defaultValue is None or isinstance(
5921 self.defaultValue, IDLNullValue
5923 # optional 'any' values always have a default value
5924 if self.optional and not self.defaultValue and not self.variadic:
5925 # Set the default value to undefined, for simplicity, so the
5926 # codegen doesn't have to special-case this.
5927 self.defaultValue = IDLUndefinedValue(self.location)
5929 if self.dictionaryMember and self.type.legacyNullToEmptyString:
5930 raise WebIDLError(
5931 "Dictionary members cannot be [LegacyNullToEmptyString]",
5932 [self.location],
5934 if self.type.isObservableArray():
5935 raise WebIDLError(
5936 "%s cannot have an ObservableArray type"
5937 % ("Dictionary members" if self.dictionaryMember else "Arguments"),
5938 [self.location],
5940 # Now do the coercing thing; this needs to happen after the
5941 # above creation of a default value.
5942 if self.defaultValue:
5943 self.defaultValue = self.defaultValue.coerceToType(self.type, self.location)
5944 assert self.defaultValue
5946 def allowTreatNonCallableAsNull(self):
5947 return self._allowTreatNonCallableAsNull
5949 def _getDependentObjects(self):
5950 deps = set([self.type])
5951 if self.defaultValue:
5952 deps.add(self.defaultValue)
5953 return deps
5955 def canHaveMissingValue(self):
5956 return self.optional and not self.defaultValue
5959 class IDLCallback(IDLObjectWithScope):
5960 def __init__(
5961 self, location, parentScope, identifier, returnType, arguments, isConstructor
5963 assert isinstance(returnType, IDLType)
5965 self._returnType = returnType
5966 # Clone the list
5967 self._arguments = list(arguments)
5969 IDLObjectWithScope.__init__(self, location, parentScope, identifier)
5971 for returnType, arguments in self.signatures():
5972 for argument in arguments:
5973 argument.resolve(self)
5975 self._treatNonCallableAsNull = False
5976 self._treatNonObjectAsNull = False
5977 self._isRunScriptBoundary = False
5978 self._isConstructor = isConstructor
5980 def isCallback(self):
5981 return True
5983 def isConstructor(self):
5984 return self._isConstructor
5986 def signatures(self):
5987 return [(self._returnType, self._arguments)]
5989 def finish(self, scope):
5990 if not self._returnType.isComplete():
5991 type = self._returnType.complete(scope)
5993 assert not isinstance(type, IDLUnresolvedType)
5994 assert not isinstance(type, IDLTypedefType)
5995 assert not isinstance(type.name, IDLUnresolvedIdentifier)
5996 self._returnType = type
5998 for argument in self._arguments:
5999 if argument.type.isComplete():
6000 continue
6002 type = argument.type.complete(scope)
6004 assert not isinstance(type, IDLUnresolvedType)
6005 assert not isinstance(type, IDLTypedefType)
6006 assert not isinstance(type.name, IDLUnresolvedIdentifier)
6007 argument.type = type
6009 def validate(self):
6010 for argument in self._arguments:
6011 if argument.type.isUndefined():
6012 raise WebIDLError(
6013 "undefined must not be used as the type of an argument in any circumstance",
6014 [self.location],
6017 def addExtendedAttributes(self, attrs):
6018 unhandledAttrs = []
6019 for attr in attrs:
6020 if attr.identifier() == "TreatNonCallableAsNull":
6021 self._treatNonCallableAsNull = True
6022 elif attr.identifier() == "LegacyTreatNonObjectAsNull":
6023 if self._isConstructor:
6024 raise WebIDLError(
6025 "[LegacyTreatNonObjectAsNull] is not supported "
6026 "on constructors",
6027 [self.location],
6029 self._treatNonObjectAsNull = True
6030 elif attr.identifier() == "MOZ_CAN_RUN_SCRIPT_BOUNDARY":
6031 if self._isConstructor:
6032 raise WebIDLError(
6033 "[MOZ_CAN_RUN_SCRIPT_BOUNDARY] is not "
6034 "permitted on constructors",
6035 [self.location],
6037 self._isRunScriptBoundary = True
6038 else:
6039 unhandledAttrs.append(attr)
6040 if self._treatNonCallableAsNull and self._treatNonObjectAsNull:
6041 raise WebIDLError(
6042 "Cannot specify both [TreatNonCallableAsNull] "
6043 "and [LegacyTreatNonObjectAsNull]",
6044 [self.location],
6046 if len(unhandledAttrs) != 0:
6047 IDLType.addExtendedAttributes(self, unhandledAttrs)
6049 def _getDependentObjects(self):
6050 return set([self._returnType] + self._arguments)
6052 def isRunScriptBoundary(self):
6053 return self._isRunScriptBoundary
6056 class IDLCallbackType(IDLType):
6057 def __init__(self, location, callback):
6058 IDLType.__init__(self, location, callback.identifier.name)
6059 self.callback = callback
6061 def isCallback(self):
6062 return True
6064 def tag(self):
6065 return IDLType.Tags.callback
6067 def isDistinguishableFrom(self, other):
6068 if other.isPromise():
6069 return False
6070 if other.isUnion():
6071 # Just forward to the union; it'll deal
6072 return other.isDistinguishableFrom(self)
6073 # Callbacks without `LegacyTreatNonObjectAsNull` are distinguishable from Dictionary likes
6074 if other.isDictionaryLike():
6075 return not self.callback._treatNonObjectAsNull
6076 return (
6077 other.isUndefined()
6078 or other.isPrimitive()
6079 or other.isString()
6080 or other.isEnum()
6081 or other.isNonCallbackInterface()
6082 or other.isSequence()
6085 def _getDependentObjects(self):
6086 return self.callback._getDependentObjects()
6089 class IDLMethodOverload:
6091 A class that represents a single overload of a WebIDL method. This is not
6092 quite the same as an element of the "effective overload set" in the spec,
6093 because separate IDLMethodOverloads are not created based on arguments being
6094 optional. Rather, when multiple methods have the same name, there is an
6095 IDLMethodOverload for each one, all hanging off an IDLMethod representing
6096 the full set of overloads.
6099 def __init__(self, returnType, arguments, location):
6100 self.returnType = returnType
6101 # Clone the list of arguments, just in case
6102 self.arguments = list(arguments)
6103 self.location = location
6105 def _getDependentObjects(self):
6106 deps = set(self.arguments)
6107 deps.add(self.returnType)
6108 return deps
6110 def includesRestrictedFloatArgument(self):
6111 return any(arg.type.includesRestrictedFloat() for arg in self.arguments)
6114 class IDLMethod(IDLInterfaceMember, IDLScope):
6115 Special = enum(
6116 "Getter", "Setter", "Deleter", "LegacyCaller", base=IDLInterfaceMember.Special
6119 NamedOrIndexed = enum("Neither", "Named", "Indexed")
6121 def __init__(
6122 self,
6123 location,
6124 identifier,
6125 returnType,
6126 arguments,
6127 static=False,
6128 getter=False,
6129 setter=False,
6130 deleter=False,
6131 specialType=NamedOrIndexed.Neither,
6132 legacycaller=False,
6133 stringifier=False,
6134 maplikeOrSetlikeOrIterable=None,
6135 underlyingAttr=None,
6137 # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up.
6138 IDLInterfaceMember.__init__(
6139 self, location, identifier, IDLInterfaceMember.Tags.Method
6142 self._hasOverloads = False
6144 assert isinstance(returnType, IDLType)
6146 # self._overloads is a list of IDLMethodOverloads
6147 self._overloads = [IDLMethodOverload(returnType, arguments, location)]
6149 assert isinstance(static, bool)
6150 self._static = static
6151 assert isinstance(getter, bool)
6152 self._getter = getter
6153 assert isinstance(setter, bool)
6154 self._setter = setter
6155 assert isinstance(deleter, bool)
6156 self._deleter = deleter
6157 assert isinstance(legacycaller, bool)
6158 self._legacycaller = legacycaller
6159 assert isinstance(stringifier, bool)
6160 self._stringifier = stringifier
6161 assert maplikeOrSetlikeOrIterable is None or isinstance(
6162 maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase
6164 self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable
6165 self._htmlConstructor = False
6166 self.underlyingAttr = underlyingAttr
6167 self._specialType = specialType
6168 self._legacyUnforgeable = False
6169 self.dependsOn = "Everything"
6170 self.affects = "Everything"
6171 self.aliases = []
6173 if static and identifier.name == "prototype":
6174 raise WebIDLError(
6175 "The identifier of a static operation must not be 'prototype'",
6176 [location],
6179 self.assertSignatureConstraints()
6181 def __str__(self):
6182 return "Method '%s'" % self.identifier
6184 def assertSignatureConstraints(self):
6185 if self._getter or self._deleter:
6186 assert len(self._overloads) == 1
6187 overload = self._overloads[0]
6188 arguments = overload.arguments
6189 assert len(arguments) == 1
6190 assert (
6191 arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.domstring]
6192 or arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]
6194 assert not arguments[0].optional and not arguments[0].variadic
6195 assert not self._getter or not overload.returnType.isUndefined()
6197 if self._setter:
6198 assert len(self._overloads) == 1
6199 arguments = self._overloads[0].arguments
6200 assert len(arguments) == 2
6201 assert (
6202 arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.domstring]
6203 or arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]
6205 assert not arguments[0].optional and not arguments[0].variadic
6206 assert not arguments[1].optional and not arguments[1].variadic
6208 if self._stringifier:
6209 assert len(self._overloads) == 1
6210 overload = self._overloads[0]
6211 assert len(overload.arguments) == 0
6212 if not self.underlyingAttr:
6213 assert (
6214 overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring]
6217 def isStatic(self):
6218 return self._static
6220 def forceStatic(self):
6221 self._static = True
6223 def isGetter(self):
6224 return self._getter
6226 def isSetter(self):
6227 return self._setter
6229 def isDeleter(self):
6230 return self._deleter
6232 def isNamed(self):
6233 assert (
6234 self._specialType == IDLMethod.NamedOrIndexed.Named
6235 or self._specialType == IDLMethod.NamedOrIndexed.Indexed
6237 return self._specialType == IDLMethod.NamedOrIndexed.Named
6239 def isIndexed(self):
6240 assert (
6241 self._specialType == IDLMethod.NamedOrIndexed.Named
6242 or self._specialType == IDLMethod.NamedOrIndexed.Indexed
6244 return self._specialType == IDLMethod.NamedOrIndexed.Indexed
6246 def isLegacycaller(self):
6247 return self._legacycaller
6249 def isStringifier(self):
6250 return self._stringifier
6252 def isToJSON(self):
6253 return self.identifier.name == "toJSON"
6255 def isDefaultToJSON(self):
6256 return self.isToJSON() and self.getExtendedAttribute("Default")
6258 def isMaplikeOrSetlikeOrIterableMethod(self):
6260 True if this method was generated as part of a
6261 maplike/setlike/etc interface (e.g. has/get methods)
6263 return self.maplikeOrSetlikeOrIterable is not None
6265 def isSpecial(self):
6266 return (
6267 self.isGetter()
6268 or self.isSetter()
6269 or self.isDeleter()
6270 or self.isLegacycaller()
6271 or self.isStringifier()
6274 def isHTMLConstructor(self):
6275 return self._htmlConstructor
6277 def hasOverloads(self):
6278 return self._hasOverloads
6280 def isIdentifierLess(self):
6282 True if the method name started with __, and if the method is not a
6283 maplike/setlike method. Interfaces with maplike/setlike will generate
6284 methods starting with __ for chrome only backing object access in JS
6285 implemented interfaces, so while these functions use what is considered
6286 an non-identifier name, they actually DO have an identifier.
6288 return (
6289 self.identifier.name[:2] == "__"
6290 and not self.isMaplikeOrSetlikeOrIterableMethod()
6293 def resolve(self, parentScope):
6294 assert isinstance(parentScope, IDLScope)
6295 IDLObjectWithIdentifier.resolve(self, parentScope)
6296 IDLScope.__init__(self, self.location, parentScope, self.identifier)
6297 for returnType, arguments in self.signatures():
6298 for argument in arguments:
6299 argument.resolve(self)
6301 def addOverload(self, method):
6302 assert len(method._overloads) == 1
6304 if self._extendedAttrDict != method._extendedAttrDict:
6305 extendedAttrDiff = set(self._extendedAttrDict.keys()) ^ set(
6306 method._extendedAttrDict.keys()
6309 if extendedAttrDiff == {"LenientFloat"}:
6310 if "LenientFloat" not in self._extendedAttrDict:
6311 for overload in self._overloads:
6312 if overload.includesRestrictedFloatArgument():
6313 raise WebIDLError(
6314 "Restricted float behavior differs on different "
6315 "overloads of %s" % method.identifier,
6316 [overload.location, method.location],
6318 self._extendedAttrDict["LenientFloat"] = method._extendedAttrDict[
6319 "LenientFloat"
6321 elif method._overloads[0].includesRestrictedFloatArgument():
6322 raise WebIDLError(
6323 "Restricted float behavior differs on different "
6324 "overloads of %s" % method.identifier,
6325 [self.location, method.location],
6327 else:
6328 raise WebIDLError(
6329 "Extended attributes differ on different "
6330 "overloads of %s" % method.identifier,
6331 [self.location, method.location],
6334 self._overloads.extend(method._overloads)
6336 self._hasOverloads = True
6338 if self.isStatic() != method.isStatic():
6339 raise WebIDLError(
6340 "Overloaded identifier %s appears with different values of the 'static' attribute"
6341 % method.identifier,
6342 [method.location],
6345 if self.isLegacycaller() != method.isLegacycaller():
6346 raise WebIDLError(
6348 "Overloaded identifier %s appears with different "
6349 "values of the 'legacycaller' attribute" % method.identifier
6351 [method.location],
6354 # Can't overload special things!
6355 if (
6356 self.isGetter()
6357 or method.isGetter()
6358 or self.isSetter()
6359 or method.isSetter()
6360 or self.isDeleter()
6361 or method.isDeleter()
6362 or self.isStringifier()
6363 or method.isStringifier()
6365 raise WebIDLError(
6366 ("Can't overload a special operation"),
6367 [self.location, method.location],
6369 if self.isHTMLConstructor() or method.isHTMLConstructor():
6370 raise WebIDLError(
6372 "An interface must contain only a single operation annotated with HTMLConstructor, and no others"
6374 [self.location, method.location],
6377 return self
6379 def signatures(self):
6380 return [
6381 (overload.returnType, overload.arguments) for overload in self._overloads
6384 def finish(self, scope):
6385 IDLInterfaceMember.finish(self, scope)
6387 for overload in self._overloads:
6388 returnType = overload.returnType
6389 if not returnType.isComplete():
6390 returnType = returnType.complete(scope)
6391 assert not isinstance(returnType, IDLUnresolvedType)
6392 assert not isinstance(returnType, IDLTypedefType)
6393 assert not isinstance(returnType.name, IDLUnresolvedIdentifier)
6394 overload.returnType = returnType
6396 for argument in overload.arguments:
6397 if not argument.isComplete():
6398 argument.complete(scope)
6399 assert argument.type.isComplete()
6401 # Now compute various information that will be used by the
6402 # WebIDL overload resolution algorithm.
6403 self.maxArgCount = max(len(s[1]) for s in self.signatures())
6404 self.allowedArgCounts = [
6406 for i in range(self.maxArgCount + 1)
6407 if len(self.signaturesForArgCount(i)) != 0
6410 def validate(self):
6411 IDLInterfaceMember.validate(self)
6413 # Make sure our overloads are properly distinguishable and don't have
6414 # different argument types before the distinguishing args.
6415 for argCount in self.allowedArgCounts:
6416 possibleOverloads = self.overloadsForArgCount(argCount)
6417 if len(possibleOverloads) == 1:
6418 continue
6419 distinguishingIndex = self.distinguishingIndexForArgCount(argCount)
6420 for idx in range(distinguishingIndex):
6421 firstSigType = possibleOverloads[0].arguments[idx].type
6422 for overload in possibleOverloads[1:]:
6423 if overload.arguments[idx].type != firstSigType:
6424 raise WebIDLError(
6425 "Signatures for method '%s' with %d arguments have "
6426 "different types of arguments at index %d, which "
6427 "is before distinguishing index %d"
6429 self.identifier.name,
6430 argCount,
6431 idx,
6432 distinguishingIndex,
6434 [self.location, overload.location],
6437 overloadWithPromiseReturnType = None
6438 overloadWithoutPromiseReturnType = None
6439 for overload in self._overloads:
6440 returnType = overload.returnType
6441 if not returnType.unroll().isExposedInAllOf(self.exposureSet):
6442 raise WebIDLError(
6443 "Overload returns a type that is not exposed "
6444 "everywhere where the method is exposed",
6445 [overload.location],
6448 variadicArgument = None
6450 arguments = overload.arguments
6451 for idx, argument in enumerate(arguments):
6452 assert argument.type.isComplete()
6454 if (
6455 argument.type.isDictionary()
6456 and argument.type.unroll().inner.canBeEmpty()
6457 ) or (
6458 argument.type.isUnion()
6459 and argument.type.unroll().hasPossiblyEmptyDictionaryType()
6461 # Optional dictionaries and unions containing optional
6462 # dictionaries at the end of the list or followed by
6463 # optional arguments must be optional.
6464 if not argument.optional and all(
6465 arg.optional for arg in arguments[idx + 1 :]
6467 raise WebIDLError(
6468 "Dictionary argument without any "
6469 "required fields or union argument "
6470 "containing such dictionary not "
6471 "followed by a required argument "
6472 "must be optional",
6473 [argument.location],
6476 if not argument.defaultValue and all(
6477 arg.optional for arg in arguments[idx + 1 :]
6479 raise WebIDLError(
6480 "Dictionary argument without any "
6481 "required fields or union argument "
6482 "containing such dictionary not "
6483 "followed by a required argument "
6484 "must have a default value",
6485 [argument.location],
6488 # An argument cannot be a nullable dictionary or a
6489 # nullable union containing a dictionary.
6490 if argument.type.nullable() and (
6491 argument.type.isDictionary()
6492 or (
6493 argument.type.isUnion()
6494 and argument.type.unroll().hasDictionaryType()
6497 raise WebIDLError(
6498 "An argument cannot be a nullable "
6499 "dictionary or nullable union "
6500 "containing a dictionary",
6501 [argument.location],
6504 # Only the last argument can be variadic
6505 if variadicArgument:
6506 raise WebIDLError(
6507 "Variadic argument is not last argument",
6508 [variadicArgument.location],
6510 if argument.variadic:
6511 variadicArgument = argument
6513 if returnType.isPromise():
6514 overloadWithPromiseReturnType = overload
6515 else:
6516 overloadWithoutPromiseReturnType = overload
6518 # Make sure either all our overloads return Promises or none do
6519 if overloadWithPromiseReturnType and overloadWithoutPromiseReturnType:
6520 raise WebIDLError(
6521 "We have overloads with both Promise and " "non-Promise return types",
6523 overloadWithPromiseReturnType.location,
6524 overloadWithoutPromiseReturnType.location,
6528 if overloadWithPromiseReturnType and self._legacycaller:
6529 raise WebIDLError(
6530 "May not have a Promise return type for a " "legacycaller.",
6531 [overloadWithPromiseReturnType.location],
6534 if self.getExtendedAttribute("StaticClassOverride") and not (
6535 self.identifier.scope.isJSImplemented() and self.isStatic()
6537 raise WebIDLError(
6538 "StaticClassOverride can be applied to static"
6539 " methods on JS-implemented classes only.",
6540 [self.location],
6543 # Ensure that toJSON methods satisfy the spec constraints on them.
6544 if self.identifier.name == "toJSON":
6545 if len(self.signatures()) != 1:
6546 raise WebIDLError(
6547 "toJSON method has multiple overloads",
6548 [self._overloads[0].location, self._overloads[1].location],
6550 if len(self.signatures()[0][1]) != 0:
6551 raise WebIDLError("toJSON method has arguments", [self.location])
6552 if not self.signatures()[0][0].isJSONType():
6553 raise WebIDLError(
6554 "toJSON method has non-JSON return type", [self.location]
6557 def overloadsForArgCount(self, argc):
6558 return [
6559 overload
6560 for overload in self._overloads
6561 if len(overload.arguments) == argc
6562 or (
6563 len(overload.arguments) > argc
6564 and all(arg.optional for arg in overload.arguments[argc:])
6566 or (
6567 len(overload.arguments) < argc
6568 and len(overload.arguments) > 0
6569 and overload.arguments[-1].variadic
6573 def signaturesForArgCount(self, argc):
6574 return [
6575 (overload.returnType, overload.arguments)
6576 for overload in self.overloadsForArgCount(argc)
6579 def locationsForArgCount(self, argc):
6580 return [overload.location for overload in self.overloadsForArgCount(argc)]
6582 def distinguishingIndexForArgCount(self, argc):
6583 def isValidDistinguishingIndex(idx, signatures):
6584 for firstSigIndex, (firstRetval, firstArgs) in enumerate(signatures[:-1]):
6585 for secondRetval, secondArgs in signatures[firstSigIndex + 1 :]:
6586 if idx < len(firstArgs):
6587 firstType = firstArgs[idx].type
6588 else:
6589 assert firstArgs[-1].variadic
6590 firstType = firstArgs[-1].type
6591 if idx < len(secondArgs):
6592 secondType = secondArgs[idx].type
6593 else:
6594 assert secondArgs[-1].variadic
6595 secondType = secondArgs[-1].type
6596 if not firstType.isDistinguishableFrom(secondType):
6597 return False
6598 return True
6600 signatures = self.signaturesForArgCount(argc)
6601 for idx in range(argc):
6602 if isValidDistinguishingIndex(idx, signatures):
6603 return idx
6604 # No valid distinguishing index. Time to throw
6605 locations = self.locationsForArgCount(argc)
6606 raise WebIDLError(
6607 "Signatures with %d arguments for method '%s' are not "
6608 "distinguishable" % (argc, self.identifier.name),
6609 locations,
6612 def handleExtendedAttribute(self, attr):
6613 identifier = attr.identifier()
6614 if (
6615 identifier == "GetterThrows"
6616 or identifier == "SetterThrows"
6617 or identifier == "GetterCanOOM"
6618 or identifier == "SetterCanOOM"
6619 or identifier == "SetterNeedsSubjectPrincipal"
6620 or identifier == "GetterNeedsSubjectPrincipal"
6622 raise WebIDLError(
6623 "Methods must not be flagged as " "[%s]" % identifier,
6624 [attr.location, self.location],
6626 elif identifier == "LegacyUnforgeable":
6627 if self.isStatic():
6628 raise WebIDLError(
6629 "[LegacyUnforgeable] is only allowed on non-static " "methods",
6630 [attr.location, self.location],
6632 self._legacyUnforgeable = True
6633 elif identifier == "SameObject":
6634 raise WebIDLError(
6635 "Methods must not be flagged as [SameObject]",
6636 [attr.location, self.location],
6638 elif identifier == "Constant":
6639 raise WebIDLError(
6640 "Methods must not be flagged as [Constant]",
6641 [attr.location, self.location],
6643 elif identifier == "PutForwards":
6644 raise WebIDLError(
6645 "Only attributes support [PutForwards]", [attr.location, self.location]
6647 elif identifier == "LegacyLenientSetter":
6648 raise WebIDLError(
6649 "Only attributes support [LegacyLenientSetter]",
6650 [attr.location, self.location],
6652 elif identifier == "LenientFloat":
6653 # This is called before we've done overload resolution
6654 overloads = self._overloads
6655 assert len(overloads) == 1
6656 if not overloads[0].returnType.isUndefined():
6657 raise WebIDLError(
6658 "[LenientFloat] used on a non-undefined method",
6659 [attr.location, self.location],
6661 if not overloads[0].includesRestrictedFloatArgument():
6662 raise WebIDLError(
6663 "[LenientFloat] used on an operation with no "
6664 "restricted float type arguments",
6665 [attr.location, self.location],
6667 elif identifier == "Exposed":
6668 convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
6669 elif (
6670 identifier == "CrossOriginCallable"
6671 or identifier == "WebGLHandlesContextLoss"
6673 # Known no-argument attributes.
6674 if not attr.noArguments():
6675 raise WebIDLError(
6676 "[%s] must take no arguments" % identifier, [attr.location]
6678 if identifier == "CrossOriginCallable" and self.isStatic():
6679 raise WebIDLError(
6680 "[CrossOriginCallable] is only allowed on non-static " "attributes",
6681 [attr.location, self.location],
6683 elif identifier == "Pure":
6684 if not attr.noArguments():
6685 raise WebIDLError("[Pure] must take no arguments", [attr.location])
6686 self._setDependsOn("DOMState")
6687 self._setAffects("Nothing")
6688 elif identifier == "Affects":
6689 if not attr.hasValue():
6690 raise WebIDLError("[Affects] takes an identifier", [attr.location])
6691 self._setAffects(attr.value())
6692 elif identifier == "DependsOn":
6693 if not attr.hasValue():
6694 raise WebIDLError("[DependsOn] takes an identifier", [attr.location])
6695 self._setDependsOn(attr.value())
6696 elif identifier == "Alias":
6697 if not attr.hasValue():
6698 raise WebIDLError(
6699 "[Alias] takes an identifier or string", [attr.location]
6701 self._addAlias(attr.value())
6702 elif identifier == "UseCounter":
6703 if self.isSpecial():
6704 raise WebIDLError(
6705 "[UseCounter] must not be used on a special " "operation",
6706 [attr.location, self.location],
6708 elif identifier == "Unscopable":
6709 if not attr.noArguments():
6710 raise WebIDLError(
6711 "[Unscopable] must take no arguments", [attr.location]
6713 if self.isStatic():
6714 raise WebIDLError(
6715 "[Unscopable] is only allowed on non-static "
6716 "attributes and operations",
6717 [attr.location, self.location],
6719 elif identifier == "CEReactions":
6720 if not attr.noArguments():
6721 raise WebIDLError(
6722 "[CEReactions] must take no arguments", [attr.location]
6725 if self.isSpecial() and not self.isSetter() and not self.isDeleter():
6726 raise WebIDLError(
6727 "[CEReactions] is only allowed on operation, "
6728 "attribute, setter, and deleter",
6729 [attr.location, self.location],
6731 elif identifier == "Default":
6732 if not attr.noArguments():
6733 raise WebIDLError("[Default] must take no arguments", [attr.location])
6735 if not self.isToJSON():
6736 raise WebIDLError(
6737 "[Default] is only allowed on toJSON operations",
6738 [attr.location, self.location],
6741 if self.signatures()[0][0] != BuiltinTypes[IDLBuiltinType.Types.object]:
6742 raise WebIDLError(
6743 "The return type of the default toJSON "
6744 "operation must be 'object'",
6745 [attr.location, self.location],
6747 elif (
6748 identifier == "Throws"
6749 or identifier == "CanOOM"
6750 or identifier == "NewObject"
6751 or identifier == "ChromeOnly"
6752 or identifier == "Pref"
6753 or identifier == "Deprecated"
6754 or identifier == "Func"
6755 or identifier == "Trial"
6756 or identifier == "SecureContext"
6757 or identifier == "BinaryName"
6758 or identifier == "NeedsSubjectPrincipal"
6759 or identifier == "NeedsCallerType"
6760 or identifier == "StaticClassOverride"
6761 or identifier == "NonEnumerable"
6762 or identifier == "Unexposed"
6763 or identifier == "WebExtensionStub"
6765 # Known attributes that we don't need to do anything with here
6766 pass
6767 else:
6768 raise WebIDLError(
6769 "Unknown extended attribute %s on method" % identifier, [attr.location]
6771 IDLInterfaceMember.handleExtendedAttribute(self, attr)
6773 def returnsPromise(self):
6774 return self._overloads[0].returnType.isPromise()
6776 def isLegacyUnforgeable(self):
6777 return self._legacyUnforgeable
6779 def _getDependentObjects(self):
6780 deps = set()
6781 for overload in self._overloads:
6782 deps.update(overload._getDependentObjects())
6783 return deps
6786 class IDLConstructor(IDLMethod):
6787 def __init__(self, location, args, name):
6788 # We can't actually init our IDLMethod yet, because we do not know the
6789 # return type yet. Just save the info we have for now and we will init
6790 # it later.
6791 self._initLocation = location
6792 self._initArgs = args
6793 self._initName = name
6794 self._inited = False
6795 self._initExtendedAttrs = []
6797 def addExtendedAttributes(self, attrs):
6798 if self._inited:
6799 return IDLMethod.addExtendedAttributes(self, attrs)
6800 self._initExtendedAttrs.extend(attrs)
6802 def handleExtendedAttribute(self, attr):
6803 identifier = attr.identifier()
6804 if (
6805 identifier == "BinaryName"
6806 or identifier == "ChromeOnly"
6807 or identifier == "NewObject"
6808 or identifier == "SecureContext"
6809 or identifier == "Throws"
6810 or identifier == "Func"
6811 or identifier == "Trial"
6812 or identifier == "Pref"
6813 or identifier == "UseCounter"
6815 IDLMethod.handleExtendedAttribute(self, attr)
6816 elif identifier == "HTMLConstructor":
6817 if not attr.noArguments():
6818 raise WebIDLError(
6819 "[HTMLConstructor] must take no arguments", [attr.location]
6821 # We shouldn't end up here for legacy factory functions.
6822 assert self.identifier.name == "constructor"
6824 if any(len(sig[1]) != 0 for sig in self.signatures()):
6825 raise WebIDLError(
6826 "[HTMLConstructor] must not be applied to a "
6827 "constructor operation that has arguments.",
6828 [attr.location],
6830 self._htmlConstructor = True
6831 else:
6832 raise WebIDLError(
6833 "Unknown extended attribute %s on method" % identifier, [attr.location]
6836 def reallyInit(self, parentInterface):
6837 name = self._initName
6838 location = self._initLocation
6839 identifier = IDLUnresolvedIdentifier(location, name, allowForbidden=True)
6840 retType = IDLWrapperType(parentInterface.location, parentInterface)
6841 IDLMethod.__init__(
6842 self, location, identifier, retType, self._initArgs, static=True
6844 self._inited = True
6845 # Propagate through whatever extended attributes we already had
6846 self.addExtendedAttributes(self._initExtendedAttrs)
6847 self._initExtendedAttrs = []
6848 # Constructors are always NewObject. Whether they throw or not is
6849 # indicated by [Throws] annotations in the usual way.
6850 self.addExtendedAttributes(
6851 [IDLExtendedAttribute(self.location, ("NewObject",))]
6855 class IDLIncludesStatement(IDLObject):
6856 def __init__(self, location, interface, mixin):
6857 IDLObject.__init__(self, location)
6858 self.interface = interface
6859 self.mixin = mixin
6860 self._finished = False
6862 def finish(self, scope):
6863 if self._finished:
6864 return
6865 self._finished = True
6866 assert isinstance(self.interface, IDLIdentifierPlaceholder)
6867 assert isinstance(self.mixin, IDLIdentifierPlaceholder)
6868 interface = self.interface.finish(scope)
6869 mixin = self.mixin.finish(scope)
6870 # NOTE: we depend on not setting self.interface and
6871 # self.mixin here to keep track of the original
6872 # locations.
6873 if not isinstance(interface, IDLInterface):
6874 raise WebIDLError(
6875 "Left-hand side of 'includes' is not an " "interface",
6876 [self.interface.location, interface.location],
6878 if interface.isCallback():
6879 raise WebIDLError(
6880 "Left-hand side of 'includes' is a callback " "interface",
6881 [self.interface.location, interface.location],
6883 if not isinstance(mixin, IDLInterfaceMixin):
6884 raise WebIDLError(
6885 "Right-hand side of 'includes' is not an " "interface mixin",
6886 [self.mixin.location, mixin.location],
6889 mixin.actualExposureGlobalNames.update(interface._exposureGlobalNames)
6891 interface.addIncludedMixin(mixin)
6892 self.interface = interface
6893 self.mixin = mixin
6895 def validate(self):
6896 pass
6898 def addExtendedAttributes(self, attrs):
6899 if len(attrs) != 0:
6900 raise WebIDLError(
6901 "There are no extended attributes that are "
6902 "allowed on includes statements",
6903 [attrs[0].location, self.location],
6907 class IDLExtendedAttribute(IDLObject):
6909 A class to represent IDL extended attributes so we can give them locations
6912 def __init__(self, location, tuple):
6913 IDLObject.__init__(self, location)
6914 self._tuple = tuple
6916 def identifier(self):
6917 return self._tuple[0]
6919 def noArguments(self):
6920 return len(self._tuple) == 1
6922 def hasValue(self):
6923 return len(self._tuple) >= 2 and isinstance(self._tuple[1], str)
6925 def value(self):
6926 assert self.hasValue()
6927 return self._tuple[1]
6929 def hasArgs(self):
6930 return (
6931 len(self._tuple) == 2
6932 and isinstance(self._tuple[1], list)
6933 or len(self._tuple) == 3
6936 def args(self):
6937 assert self.hasArgs()
6938 # Our args are our last element
6939 return self._tuple[-1]
6941 def listValue(self):
6943 Backdoor for storing random data in _extendedAttrDict
6945 return list(self._tuple)[1:]
6948 # Parser
6951 class Tokenizer(object):
6952 tokens = ["INTEGER", "FLOATLITERAL", "IDENTIFIER", "STRING", "WHITESPACE", "OTHER"]
6954 def t_FLOATLITERAL(self, t):
6955 r"(-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+|Infinity))|NaN"
6956 t.value = float(t.value)
6957 return t
6959 def t_INTEGER(self, t):
6960 r"-?(0([0-7]+|[Xx][0-9A-Fa-f]+)?|[1-9][0-9]*)"
6961 try:
6962 # Can't use int(), because that doesn't handle octal properly.
6963 t.value = parseInt(t.value)
6964 except Exception:
6965 raise WebIDLError(
6966 "Invalid integer literal",
6968 Location(
6969 lexer=self.lexer,
6970 lineno=self.lexer.lineno,
6971 lexpos=self.lexer.lexpos,
6972 filename=self._filename,
6976 return t
6978 def t_IDENTIFIER(self, t):
6979 r"[_-]?[A-Za-z][0-9A-Z_a-z-]*"
6980 t.type = self.keywords.get(t.value, "IDENTIFIER")
6981 return t
6983 def t_STRING(self, t):
6984 r'"[^"]*"'
6985 t.value = t.value[1:-1]
6986 return t
6988 def t_WHITESPACE(self, t):
6989 r"[\t\n\r ]+|[\t\n\r ]*((//[^\n]*|/\*.*?\*/)[\t\n\r ]*)+"
6990 pass
6992 def t_ELLIPSIS(self, t):
6993 r"\.\.\."
6994 t.type = self.keywords.get(t.value)
6995 return t
6997 def t_OTHER(self, t):
6998 r"[^\t\n\r 0-9A-Z_a-z]"
6999 t.type = self.keywords.get(t.value, "OTHER")
7000 return t
7002 keywords = {
7003 "interface": "INTERFACE",
7004 "partial": "PARTIAL",
7005 "mixin": "MIXIN",
7006 "dictionary": "DICTIONARY",
7007 "exception": "EXCEPTION",
7008 "enum": "ENUM",
7009 "callback": "CALLBACK",
7010 "typedef": "TYPEDEF",
7011 "includes": "INCLUDES",
7012 "const": "CONST",
7013 "null": "NULL",
7014 "true": "TRUE",
7015 "false": "FALSE",
7016 "serializer": "SERIALIZER",
7017 "stringifier": "STRINGIFIER",
7018 "unrestricted": "UNRESTRICTED",
7019 "attribute": "ATTRIBUTE",
7020 "readonly": "READONLY",
7021 "inherit": "INHERIT",
7022 "static": "STATIC",
7023 "getter": "GETTER",
7024 "setter": "SETTER",
7025 "deleter": "DELETER",
7026 "legacycaller": "LEGACYCALLER",
7027 "optional": "OPTIONAL",
7028 "...": "ELLIPSIS",
7029 "::": "SCOPE",
7030 "DOMString": "DOMSTRING",
7031 "ByteString": "BYTESTRING",
7032 "USVString": "USVSTRING",
7033 "JSString": "JSSTRING",
7034 "UTF8String": "UTF8STRING",
7035 "any": "ANY",
7036 "boolean": "BOOLEAN",
7037 "byte": "BYTE",
7038 "double": "DOUBLE",
7039 "float": "FLOAT",
7040 "long": "LONG",
7041 "object": "OBJECT",
7042 "ObservableArray": "OBSERVABLEARRAY",
7043 "octet": "OCTET",
7044 "Promise": "PROMISE",
7045 "required": "REQUIRED",
7046 "sequence": "SEQUENCE",
7047 "record": "RECORD",
7048 "short": "SHORT",
7049 "unsigned": "UNSIGNED",
7050 "undefined": "UNDEFINED",
7051 ":": "COLON",
7052 ";": "SEMICOLON",
7053 "{": "LBRACE",
7054 "}": "RBRACE",
7055 "(": "LPAREN",
7056 ")": "RPAREN",
7057 "[": "LBRACKET",
7058 "]": "RBRACKET",
7059 "?": "QUESTIONMARK",
7060 "*": "ASTERISK",
7061 ",": "COMMA",
7062 "=": "EQUALS",
7063 "<": "LT",
7064 ">": "GT",
7065 "ArrayBuffer": "ARRAYBUFFER",
7066 "or": "OR",
7067 "maplike": "MAPLIKE",
7068 "setlike": "SETLIKE",
7069 "iterable": "ITERABLE",
7070 "namespace": "NAMESPACE",
7071 "constructor": "CONSTRUCTOR",
7072 "symbol": "SYMBOL",
7073 "async": "ASYNC",
7076 tokens.extend(keywords.values())
7078 def t_error(self, t):
7079 raise WebIDLError(
7080 "Unrecognized Input",
7082 Location(
7083 lexer=self.lexer,
7084 lineno=self.lexer.lineno,
7085 lexpos=self.lexer.lexpos,
7086 filename=self._filename,
7091 def __init__(self, outputdir, lexer=None):
7092 if lexer:
7093 self.lexer = lexer
7094 else:
7095 self.lexer = lex.lex(object=self, reflags=re.DOTALL)
7098 class SqueakyCleanLogger(object):
7099 errorWhitelist = [
7100 # Web IDL defines the WHITESPACE token, but doesn't actually
7101 # use it ... so far.
7102 "Token 'WHITESPACE' defined, but not used",
7103 # And that means we have an unused token
7104 "There is 1 unused token",
7105 # Web IDL defines a OtherOrComma rule that's only used in
7106 # ExtendedAttributeInner, which we don't use yet.
7107 "Rule 'OtherOrComma' defined, but not used",
7108 # And an unused rule
7109 "There is 1 unused rule",
7110 # And the OtherOrComma grammar symbol is unreachable.
7111 "Symbol 'OtherOrComma' is unreachable",
7112 # Which means the Other symbol is unreachable.
7113 "Symbol 'Other' is unreachable",
7116 def __init__(self):
7117 self.errors = []
7119 def debug(self, msg, *args, **kwargs):
7120 pass
7122 info = debug
7124 def warning(self, msg, *args, **kwargs):
7125 if (
7126 msg == "%s:%d: Rule %r defined, but not used"
7127 or msg == "%s:%d: Rule '%s' defined, but not used"
7129 # Munge things so we don't have to hardcode filenames and
7130 # line numbers in our whitelist.
7131 whitelistmsg = "Rule %r defined, but not used"
7132 whitelistargs = args[2:]
7133 else:
7134 whitelistmsg = msg
7135 whitelistargs = args
7136 if (whitelistmsg % whitelistargs) not in SqueakyCleanLogger.errorWhitelist:
7137 self.errors.append(msg % args)
7139 error = warning
7141 def reportGrammarErrors(self):
7142 if self.errors:
7143 raise WebIDLError("\n".join(self.errors), [])
7146 class Parser(Tokenizer):
7147 def getLocation(self, p, i):
7148 return Location(self.lexer, p.lineno(i), p.lexpos(i), self._filename)
7150 def globalScope(self):
7151 return self._globalScope
7153 # The p_Foo functions here must match the WebIDL spec's grammar.
7154 # It's acceptable to split things at '|' boundaries.
7155 def p_Definitions(self, p):
7157 Definitions : ExtendedAttributeList Definition Definitions
7159 if p[2]:
7160 p[0] = [p[2]]
7161 p[2].addExtendedAttributes(p[1])
7162 else:
7163 assert not p[1]
7164 p[0] = []
7166 p[0].extend(p[3])
7168 def p_DefinitionsEmpty(self, p):
7170 Definitions :
7172 p[0] = []
7174 def p_Definition(self, p):
7176 Definition : CallbackOrInterfaceOrMixin
7177 | Namespace
7178 | Partial
7179 | Dictionary
7180 | Exception
7181 | Enum
7182 | Typedef
7183 | IncludesStatement
7185 p[0] = p[1]
7186 assert p[1] # We might not have implemented something ...
7188 def p_CallbackOrInterfaceOrMixinCallback(self, p):
7190 CallbackOrInterfaceOrMixin : CALLBACK CallbackRestOrInterface
7192 if p[2].isInterface():
7193 assert isinstance(p[2], IDLInterface)
7194 p[2].setCallback(True)
7196 p[0] = p[2]
7198 def p_CallbackOrInterfaceOrMixinInterfaceOrMixin(self, p):
7200 CallbackOrInterfaceOrMixin : INTERFACE InterfaceOrMixin
7202 p[0] = p[2]
7204 def p_CallbackRestOrInterface(self, p):
7206 CallbackRestOrInterface : CallbackRest
7207 | CallbackConstructorRest
7208 | CallbackInterface
7210 assert p[1]
7211 p[0] = p[1]
7213 def handleNonPartialObject(
7214 self, location, identifier, constructor, constructorArgs, nonPartialArgs
7217 This handles non-partial objects (interfaces, namespaces and
7218 dictionaries) by checking for an existing partial object, and promoting
7219 it to non-partial as needed. The return value is the non-partial
7220 object.
7222 constructorArgs are all the args for the constructor except the last
7223 one: isKnownNonPartial.
7225 nonPartialArgs are the args for the setNonPartial call.
7227 # The name of the class starts with "IDL", so strip that off.
7228 # Also, starts with a capital letter after that, so nix that
7229 # as well.
7230 prettyname = constructor.__name__[3:].lower()
7232 try:
7233 existingObj = self.globalScope()._lookupIdentifier(identifier)
7234 if existingObj:
7235 if not isinstance(existingObj, constructor):
7236 raise WebIDLError(
7237 "%s has the same name as "
7238 "non-%s object" % (prettyname.capitalize(), prettyname),
7239 [location, existingObj.location],
7241 existingObj.setNonPartial(*nonPartialArgs)
7242 return existingObj
7243 except Exception as ex:
7244 if isinstance(ex, WebIDLError):
7245 raise ex
7246 pass
7248 # True for isKnownNonPartial
7249 return constructor(*(constructorArgs + [True]))
7251 def p_InterfaceOrMixin(self, p):
7253 InterfaceOrMixin : InterfaceRest
7254 | MixinRest
7256 p[0] = p[1]
7258 def p_CallbackInterface(self, p):
7260 CallbackInterface : INTERFACE InterfaceRest
7262 p[0] = p[2]
7264 def p_InterfaceRest(self, p):
7266 InterfaceRest : IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON
7268 location = self.getLocation(p, 1)
7269 identifier = IDLUnresolvedIdentifier(location, p[1])
7270 members = p[4]
7271 parent = p[2]
7273 p[0] = self.handleNonPartialObject(
7274 location,
7275 identifier,
7276 IDLInterface,
7277 [location, self.globalScope(), identifier, parent, members],
7278 [location, parent, members],
7281 def p_InterfaceForwardDecl(self, p):
7283 InterfaceRest : IDENTIFIER SEMICOLON
7285 location = self.getLocation(p, 1)
7286 identifier = IDLUnresolvedIdentifier(location, p[1])
7288 try:
7289 if self.globalScope()._lookupIdentifier(identifier):
7290 p[0] = self.globalScope()._lookupIdentifier(identifier)
7291 if not isinstance(p[0], IDLExternalInterface):
7292 raise WebIDLError(
7293 "Name collision between external "
7294 "interface declaration for identifier "
7295 "%s and %s" % (identifier.name, p[0]),
7296 [location, p[0].location],
7298 return
7299 except Exception as ex:
7300 if isinstance(ex, WebIDLError):
7301 raise ex
7302 pass
7304 p[0] = IDLExternalInterface(location, self.globalScope(), identifier)
7306 def p_MixinRest(self, p):
7308 MixinRest : MIXIN IDENTIFIER LBRACE MixinMembers RBRACE SEMICOLON
7310 location = self.getLocation(p, 1)
7311 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
7312 members = p[4]
7314 p[0] = self.handleNonPartialObject(
7315 location,
7316 identifier,
7317 IDLInterfaceMixin,
7318 [location, self.globalScope(), identifier, members],
7319 [location, members],
7322 def p_Namespace(self, p):
7324 Namespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON
7326 location = self.getLocation(p, 1)
7327 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
7328 members = p[4]
7330 p[0] = self.handleNonPartialObject(
7331 location,
7332 identifier,
7333 IDLNamespace,
7334 [location, self.globalScope(), identifier, members],
7335 [location, None, members],
7338 def p_Partial(self, p):
7340 Partial : PARTIAL PartialDefinition
7342 p[0] = p[2]
7344 def p_PartialDefinitionInterface(self, p):
7346 PartialDefinition : INTERFACE PartialInterfaceOrPartialMixin
7348 p[0] = p[2]
7350 def p_PartialDefinition(self, p):
7352 PartialDefinition : PartialNamespace
7353 | PartialDictionary
7355 p[0] = p[1]
7357 def handlePartialObject(
7358 self,
7359 location,
7360 identifier,
7361 nonPartialConstructor,
7362 nonPartialConstructorArgs,
7363 partialConstructorArgs,
7366 This handles partial objects (interfaces, namespaces and dictionaries)
7367 by checking for an existing non-partial object, and adding ourselves to
7368 it as needed. The return value is our partial object. We use
7369 IDLPartialInterfaceOrNamespace for partial interfaces or namespaces,
7370 and IDLPartialDictionary for partial dictionaries.
7372 nonPartialConstructorArgs are all the args for the non-partial
7373 constructor except the last two: members and isKnownNonPartial.
7375 partialConstructorArgs are the arguments for the partial object
7376 constructor, except the last one (the non-partial object).
7378 # The name of the class starts with "IDL", so strip that off.
7379 # Also, starts with a capital letter after that, so nix that
7380 # as well.
7381 prettyname = nonPartialConstructor.__name__[3:].lower()
7383 nonPartialObject = None
7384 try:
7385 nonPartialObject = self.globalScope()._lookupIdentifier(identifier)
7386 if nonPartialObject:
7387 if not isinstance(nonPartialObject, nonPartialConstructor):
7388 raise WebIDLError(
7389 "Partial %s has the same name as "
7390 "non-%s object" % (prettyname, prettyname),
7391 [location, nonPartialObject.location],
7393 except Exception as ex:
7394 if isinstance(ex, WebIDLError):
7395 raise ex
7396 pass
7398 if not nonPartialObject:
7399 nonPartialObject = nonPartialConstructor(
7400 # No members, False for isKnownNonPartial
7401 *(nonPartialConstructorArgs),
7402 members=[],
7403 isKnownNonPartial=False
7406 partialObject = None
7407 if isinstance(nonPartialObject, IDLDictionary):
7408 partialObject = IDLPartialDictionary(
7409 *(partialConstructorArgs + [nonPartialObject])
7411 elif isinstance(
7412 nonPartialObject, (IDLInterface, IDLInterfaceMixin, IDLNamespace)
7414 partialObject = IDLPartialInterfaceOrNamespace(
7415 *(partialConstructorArgs + [nonPartialObject])
7417 else:
7418 raise WebIDLError(
7419 "Unknown partial object type %s" % type(partialObject), [location]
7422 return partialObject
7424 def p_PartialInterfaceOrPartialMixin(self, p):
7426 PartialInterfaceOrPartialMixin : PartialInterfaceRest
7427 | PartialMixinRest
7429 p[0] = p[1]
7431 def p_PartialInterfaceRest(self, p):
7433 PartialInterfaceRest : IDENTIFIER LBRACE PartialInterfaceMembers RBRACE SEMICOLON
7435 location = self.getLocation(p, 1)
7436 identifier = IDLUnresolvedIdentifier(location, p[1])
7437 members = p[3]
7439 p[0] = self.handlePartialObject(
7440 location,
7441 identifier,
7442 IDLInterface,
7443 [location, self.globalScope(), identifier, None],
7444 [location, identifier, members],
7447 def p_PartialMixinRest(self, p):
7449 PartialMixinRest : MIXIN IDENTIFIER LBRACE MixinMembers RBRACE SEMICOLON
7451 location = self.getLocation(p, 1)
7452 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
7453 members = p[4]
7455 p[0] = self.handlePartialObject(
7456 location,
7457 identifier,
7458 IDLInterfaceMixin,
7459 [location, self.globalScope(), identifier],
7460 [location, identifier, members],
7463 def p_PartialNamespace(self, p):
7465 PartialNamespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON
7467 location = self.getLocation(p, 1)
7468 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
7469 members = p[4]
7471 p[0] = self.handlePartialObject(
7472 location,
7473 identifier,
7474 IDLNamespace,
7475 [location, self.globalScope(), identifier],
7476 [location, identifier, members],
7479 def p_PartialDictionary(self, p):
7481 PartialDictionary : DICTIONARY IDENTIFIER LBRACE DictionaryMembers RBRACE SEMICOLON
7483 location = self.getLocation(p, 1)
7484 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
7485 members = p[4]
7487 p[0] = self.handlePartialObject(
7488 location,
7489 identifier,
7490 IDLDictionary,
7491 [location, self.globalScope(), identifier],
7492 [location, identifier, members],
7495 def p_Inheritance(self, p):
7497 Inheritance : COLON ScopedName
7499 p[0] = IDLIdentifierPlaceholder(self.getLocation(p, 2), p[2])
7501 def p_InheritanceEmpty(self, p):
7503 Inheritance :
7505 pass
7507 def p_InterfaceMembers(self, p):
7509 InterfaceMembers : ExtendedAttributeList InterfaceMember InterfaceMembers
7511 p[0] = [p[2]]
7513 assert not p[1] or p[2]
7514 p[2].addExtendedAttributes(p[1])
7516 p[0].extend(p[3])
7518 def p_InterfaceMembersEmpty(self, p):
7520 InterfaceMembers :
7522 p[0] = []
7524 def p_InterfaceMember(self, p):
7526 InterfaceMember : PartialInterfaceMember
7527 | Constructor
7529 p[0] = p[1]
7531 def p_Constructor(self, p):
7533 Constructor : CONSTRUCTOR LPAREN ArgumentList RPAREN SEMICOLON
7535 p[0] = IDLConstructor(self.getLocation(p, 1), p[3], "constructor")
7537 def p_PartialInterfaceMembers(self, p):
7539 PartialInterfaceMembers : ExtendedAttributeList PartialInterfaceMember PartialInterfaceMembers
7541 p[0] = [p[2]]
7543 assert not p[1] or p[2]
7544 p[2].addExtendedAttributes(p[1])
7546 p[0].extend(p[3])
7548 def p_PartialInterfaceMembersEmpty(self, p):
7550 PartialInterfaceMembers :
7552 p[0] = []
7554 def p_PartialInterfaceMember(self, p):
7556 PartialInterfaceMember : Const
7557 | AttributeOrOperationOrMaplikeOrSetlikeOrIterable
7559 p[0] = p[1]
7561 def p_MixinMembersEmpty(self, p):
7563 MixinMembers :
7565 p[0] = []
7567 def p_MixinMembers(self, p):
7569 MixinMembers : ExtendedAttributeList MixinMember MixinMembers
7571 p[0] = [p[2]]
7573 assert not p[1] or p[2]
7574 p[2].addExtendedAttributes(p[1])
7576 p[0].extend(p[3])
7578 def p_MixinMember(self, p):
7580 MixinMember : Const
7581 | Attribute
7582 | Operation
7584 p[0] = p[1]
7586 def p_Dictionary(self, p):
7588 Dictionary : DICTIONARY IDENTIFIER Inheritance LBRACE DictionaryMembers RBRACE SEMICOLON
7590 location = self.getLocation(p, 1)
7591 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
7592 members = p[5]
7593 p[0] = IDLDictionary(location, self.globalScope(), identifier, p[3], members)
7595 def p_DictionaryMembers(self, p):
7597 DictionaryMembers : ExtendedAttributeList DictionaryMember DictionaryMembers
7600 if len(p) == 1:
7601 # We're at the end of the list
7602 p[0] = []
7603 return
7604 p[2].addExtendedAttributes(p[1])
7605 p[0] = [p[2]]
7606 p[0].extend(p[3])
7608 def p_DictionaryMemberRequired(self, p):
7610 DictionaryMember : REQUIRED TypeWithExtendedAttributes IDENTIFIER SEMICOLON
7612 # These quack a lot like required arguments, so just treat them that way.
7613 t = p[2]
7614 assert isinstance(t, IDLType)
7615 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3])
7617 p[0] = IDLArgument(
7618 self.getLocation(p, 3),
7619 identifier,
7621 optional=False,
7622 defaultValue=None,
7623 variadic=False,
7624 dictionaryMember=True,
7627 def p_DictionaryMember(self, p):
7629 DictionaryMember : Type IDENTIFIER Default SEMICOLON
7631 # These quack a lot like optional arguments, so just treat them that way.
7632 t = p[1]
7633 assert isinstance(t, IDLType)
7634 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
7635 defaultValue = p[3]
7637 # Any attributes that precede this may apply to the type, so
7638 # we configure the argument to forward type attributes down instead of producing
7639 # a parse error
7640 p[0] = IDLArgument(
7641 self.getLocation(p, 2),
7642 identifier,
7644 optional=True,
7645 defaultValue=defaultValue,
7646 variadic=False,
7647 dictionaryMember=True,
7648 allowTypeAttributes=True,
7651 def p_Default(self, p):
7653 Default : EQUALS DefaultValue
7656 if len(p) > 1:
7657 p[0] = p[2]
7658 else:
7659 p[0] = None
7661 def p_DefaultValue(self, p):
7663 DefaultValue : ConstValue
7664 | LBRACKET RBRACKET
7665 | LBRACE RBRACE
7667 if len(p) == 2:
7668 p[0] = p[1]
7669 else:
7670 assert len(p) == 3 # Must be [] or {}
7671 if p[1] == "[":
7672 p[0] = IDLEmptySequenceValue(self.getLocation(p, 1))
7673 else:
7674 assert p[1] == "{"
7675 p[0] = IDLDefaultDictionaryValue(self.getLocation(p, 1))
7677 def p_DefaultValueNull(self, p):
7679 DefaultValue : NULL
7681 p[0] = IDLNullValue(self.getLocation(p, 1))
7683 def p_DefaultValueUndefined(self, p):
7685 DefaultValue : UNDEFINED
7687 p[0] = IDLUndefinedValue(self.getLocation(p, 1))
7689 def p_Exception(self, p):
7691 Exception : EXCEPTION IDENTIFIER Inheritance LBRACE ExceptionMembers RBRACE SEMICOLON
7693 pass
7695 def p_Enum(self, p):
7697 Enum : ENUM IDENTIFIER LBRACE EnumValueList RBRACE SEMICOLON
7699 location = self.getLocation(p, 1)
7700 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
7702 values = p[4]
7703 assert values
7704 p[0] = IDLEnum(location, self.globalScope(), identifier, values)
7706 def p_EnumValueList(self, p):
7708 EnumValueList : STRING EnumValueListComma
7710 p[0] = [p[1]]
7711 p[0].extend(p[2])
7713 def p_EnumValueListComma(self, p):
7715 EnumValueListComma : COMMA EnumValueListString
7717 p[0] = p[2]
7719 def p_EnumValueListCommaEmpty(self, p):
7721 EnumValueListComma :
7723 p[0] = []
7725 def p_EnumValueListString(self, p):
7727 EnumValueListString : STRING EnumValueListComma
7729 p[0] = [p[1]]
7730 p[0].extend(p[2])
7732 def p_EnumValueListStringEmpty(self, p):
7734 EnumValueListString :
7736 p[0] = []
7738 def p_CallbackRest(self, p):
7740 CallbackRest : IDENTIFIER EQUALS Type LPAREN ArgumentList RPAREN SEMICOLON
7742 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1])
7743 p[0] = IDLCallback(
7744 self.getLocation(p, 1),
7745 self.globalScope(),
7746 identifier,
7747 p[3],
7748 p[5],
7749 isConstructor=False,
7752 def p_CallbackConstructorRest(self, p):
7754 CallbackConstructorRest : CONSTRUCTOR IDENTIFIER EQUALS Type LPAREN ArgumentList RPAREN SEMICOLON
7756 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
7757 p[0] = IDLCallback(
7758 self.getLocation(p, 2),
7759 self.globalScope(),
7760 identifier,
7761 p[4],
7762 p[6],
7763 isConstructor=True,
7766 def p_ExceptionMembers(self, p):
7768 ExceptionMembers : ExtendedAttributeList ExceptionMember ExceptionMembers
7771 pass
7773 def p_Typedef(self, p):
7775 Typedef : TYPEDEF TypeWithExtendedAttributes IDENTIFIER SEMICOLON
7777 typedef = IDLTypedef(self.getLocation(p, 1), self.globalScope(), p[2], p[3])
7778 p[0] = typedef
7780 def p_IncludesStatement(self, p):
7782 IncludesStatement : ScopedName INCLUDES ScopedName SEMICOLON
7784 assert p[2] == "includes"
7785 interface = IDLIdentifierPlaceholder(self.getLocation(p, 1), p[1])
7786 mixin = IDLIdentifierPlaceholder(self.getLocation(p, 3), p[3])
7787 p[0] = IDLIncludesStatement(self.getLocation(p, 1), interface, mixin)
7789 def p_Const(self, p):
7791 Const : CONST ConstType IDENTIFIER EQUALS ConstValue SEMICOLON
7793 location = self.getLocation(p, 1)
7794 type = p[2]
7795 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3])
7796 value = p[5]
7797 p[0] = IDLConst(location, identifier, type, value)
7799 def p_ConstValueBoolean(self, p):
7801 ConstValue : BooleanLiteral
7803 location = self.getLocation(p, 1)
7804 booleanType = BuiltinTypes[IDLBuiltinType.Types.boolean]
7805 p[0] = IDLValue(location, booleanType, p[1])
7807 def p_ConstValueInteger(self, p):
7809 ConstValue : INTEGER
7811 location = self.getLocation(p, 1)
7813 # We don't know ahead of time what type the integer literal is.
7814 # Determine the smallest type it could possibly fit in and use that.
7815 integerType = matchIntegerValueToType(p[1])
7816 if integerType is None:
7817 raise WebIDLError("Integer literal out of range", [location])
7819 p[0] = IDLValue(location, integerType, p[1])
7821 def p_ConstValueFloat(self, p):
7823 ConstValue : FLOATLITERAL
7825 location = self.getLocation(p, 1)
7826 p[0] = IDLValue(
7827 location, BuiltinTypes[IDLBuiltinType.Types.unrestricted_float], p[1]
7830 def p_ConstValueString(self, p):
7832 ConstValue : STRING
7834 location = self.getLocation(p, 1)
7835 stringType = BuiltinTypes[IDLBuiltinType.Types.domstring]
7836 p[0] = IDLValue(location, stringType, p[1])
7838 def p_BooleanLiteralTrue(self, p):
7840 BooleanLiteral : TRUE
7842 p[0] = True
7844 def p_BooleanLiteralFalse(self, p):
7846 BooleanLiteral : FALSE
7848 p[0] = False
7850 def p_AttributeOrOperationOrMaplikeOrSetlikeOrIterable(self, p):
7852 AttributeOrOperationOrMaplikeOrSetlikeOrIterable : Attribute
7853 | Maplike
7854 | Setlike
7855 | Iterable
7856 | AsyncIterable
7857 | Operation
7859 p[0] = p[1]
7861 def p_Iterable(self, p):
7863 Iterable : ITERABLE LT TypeWithExtendedAttributes GT SEMICOLON
7864 | ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON
7866 location = self.getLocation(p, 2)
7867 identifier = IDLUnresolvedIdentifier(
7868 location, "__iterable", allowDoubleUnderscore=True
7870 if len(p) > 6:
7871 keyType = p[3]
7872 valueType = p[5]
7873 else:
7874 keyType = None
7875 valueType = p[3]
7877 p[0] = IDLIterable(location, identifier, keyType, valueType, self.globalScope())
7879 def p_AsyncIterable(self, p):
7881 AsyncIterable : ASYNC ITERABLE LT TypeWithExtendedAttributes GT SEMICOLON
7882 | ASYNC ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON
7883 | ASYNC ITERABLE LT TypeWithExtendedAttributes GT LPAREN ArgumentList RPAREN SEMICOLON
7884 | ASYNC ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT LPAREN ArgumentList RPAREN SEMICOLON
7886 location = self.getLocation(p, 2)
7887 identifier = IDLUnresolvedIdentifier(
7888 location, "__iterable", allowDoubleUnderscore=True
7890 if len(p) == 12:
7891 keyType = p[4]
7892 valueType = p[6]
7893 argList = p[9]
7894 elif len(p) == 10:
7895 keyType = None
7896 valueType = p[4]
7897 argList = p[7]
7898 elif len(p) == 9:
7899 keyType = p[4]
7900 valueType = p[6]
7901 argList = []
7902 else:
7903 keyType = None
7904 valueType = p[4]
7905 argList = []
7907 p[0] = IDLAsyncIterable(
7908 location, identifier, keyType, valueType, argList, self.globalScope()
7911 def p_Setlike(self, p):
7913 Setlike : ReadOnly SETLIKE LT TypeWithExtendedAttributes GT SEMICOLON
7915 readonly = p[1]
7916 maplikeOrSetlikeType = p[2]
7917 location = self.getLocation(p, 2)
7918 identifier = IDLUnresolvedIdentifier(
7919 location, "__setlike", allowDoubleUnderscore=True
7921 keyType = p[4]
7922 valueType = keyType
7923 p[0] = IDLMaplikeOrSetlike(
7924 location, identifier, maplikeOrSetlikeType, readonly, keyType, valueType
7927 def p_Maplike(self, p):
7929 Maplike : ReadOnly MAPLIKE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON
7931 readonly = p[1]
7932 maplikeOrSetlikeType = p[2]
7933 location = self.getLocation(p, 2)
7934 identifier = IDLUnresolvedIdentifier(
7935 location, "__maplike", allowDoubleUnderscore=True
7937 keyType = p[4]
7938 valueType = p[6]
7939 p[0] = IDLMaplikeOrSetlike(
7940 location, identifier, maplikeOrSetlikeType, readonly, keyType, valueType
7943 def p_AttributeWithQualifier(self, p):
7945 Attribute : Qualifier AttributeRest
7947 static = IDLInterfaceMember.Special.Static in p[1]
7948 stringifier = IDLInterfaceMember.Special.Stringifier in p[1]
7949 (location, identifier, type, readonly) = p[2]
7950 p[0] = IDLAttribute(
7951 location, identifier, type, readonly, static=static, stringifier=stringifier
7954 def p_AttributeInherited(self, p):
7956 Attribute : INHERIT AttributeRest
7958 (location, identifier, type, readonly) = p[2]
7959 p[0] = IDLAttribute(location, identifier, type, readonly, inherit=True)
7961 def p_Attribute(self, p):
7963 Attribute : AttributeRest
7965 (location, identifier, type, readonly) = p[1]
7966 p[0] = IDLAttribute(location, identifier, type, readonly, inherit=False)
7968 def p_AttributeRest(self, p):
7970 AttributeRest : ReadOnly ATTRIBUTE TypeWithExtendedAttributes AttributeName SEMICOLON
7972 location = self.getLocation(p, 2)
7973 readonly = p[1]
7974 t = p[3]
7975 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 4), p[4])
7976 p[0] = (location, identifier, t, readonly)
7978 def p_ReadOnly(self, p):
7980 ReadOnly : READONLY
7982 p[0] = True
7984 def p_ReadOnlyEmpty(self, p):
7986 ReadOnly :
7988 p[0] = False
7990 def p_Operation(self, p):
7992 Operation : Qualifiers OperationRest
7994 qualifiers = p[1]
7996 # Disallow duplicates in the qualifier set
7997 if not len(set(qualifiers)) == len(qualifiers):
7998 raise WebIDLError(
7999 "Duplicate qualifiers are not allowed", [self.getLocation(p, 1)]
8002 static = IDLInterfaceMember.Special.Static in p[1]
8003 # If static is there that's all that's allowed. This is disallowed
8004 # by the parser, so we can assert here.
8005 assert not static or len(qualifiers) == 1
8007 stringifier = IDLInterfaceMember.Special.Stringifier in p[1]
8008 # If stringifier is there that's all that's allowed. This is disallowed
8009 # by the parser, so we can assert here.
8010 assert not stringifier or len(qualifiers) == 1
8012 getter = True if IDLMethod.Special.Getter in p[1] else False
8013 setter = True if IDLMethod.Special.Setter in p[1] else False
8014 deleter = True if IDLMethod.Special.Deleter in p[1] else False
8015 legacycaller = True if IDLMethod.Special.LegacyCaller in p[1] else False
8017 if getter or deleter:
8018 if setter:
8019 raise WebIDLError(
8020 "getter and deleter are incompatible with setter",
8021 [self.getLocation(p, 1)],
8024 (returnType, identifier, arguments) = p[2]
8026 assert isinstance(returnType, IDLType)
8028 specialType = IDLMethod.NamedOrIndexed.Neither
8030 if getter or deleter:
8031 if len(arguments) != 1:
8032 raise WebIDLError(
8033 "%s has wrong number of arguments"
8034 % ("getter" if getter else "deleter"),
8035 [self.getLocation(p, 2)],
8037 argType = arguments[0].type
8038 if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]:
8039 specialType = IDLMethod.NamedOrIndexed.Named
8040 elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]:
8041 specialType = IDLMethod.NamedOrIndexed.Indexed
8042 if deleter:
8043 raise WebIDLError(
8044 "There is no such thing as an indexed deleter.",
8045 [self.getLocation(p, 1)],
8047 else:
8048 raise WebIDLError(
8049 "%s has wrong argument type (must be DOMString or UnsignedLong)"
8050 % ("getter" if getter else "deleter"),
8051 [arguments[0].location],
8053 if arguments[0].optional or arguments[0].variadic:
8054 raise WebIDLError(
8055 "%s cannot have %s argument"
8057 "getter" if getter else "deleter",
8058 "optional" if arguments[0].optional else "variadic",
8060 [arguments[0].location],
8062 if getter:
8063 if returnType.isUndefined():
8064 raise WebIDLError(
8065 "getter cannot have undefined return type", [self.getLocation(p, 2)]
8067 if setter:
8068 if len(arguments) != 2:
8069 raise WebIDLError(
8070 "setter has wrong number of arguments", [self.getLocation(p, 2)]
8072 argType = arguments[0].type
8073 if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]:
8074 specialType = IDLMethod.NamedOrIndexed.Named
8075 elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]:
8076 specialType = IDLMethod.NamedOrIndexed.Indexed
8077 else:
8078 raise WebIDLError(
8079 "settter has wrong argument type (must be DOMString or UnsignedLong)",
8080 [arguments[0].location],
8082 if arguments[0].optional or arguments[0].variadic:
8083 raise WebIDLError(
8084 "setter cannot have %s argument"
8085 % ("optional" if arguments[0].optional else "variadic"),
8086 [arguments[0].location],
8088 if arguments[1].optional or arguments[1].variadic:
8089 raise WebIDLError(
8090 "setter cannot have %s argument"
8091 % ("optional" if arguments[1].optional else "variadic"),
8092 [arguments[1].location],
8095 if stringifier:
8096 if len(arguments) != 0:
8097 raise WebIDLError(
8098 "stringifier has wrong number of arguments",
8099 [self.getLocation(p, 2)],
8101 if not returnType.isDOMString():
8102 raise WebIDLError(
8103 "stringifier must have DOMString return type",
8104 [self.getLocation(p, 2)],
8107 # identifier might be None. This is only permitted for special methods.
8108 if not identifier:
8109 if (
8110 not getter
8111 and not setter
8112 and not deleter
8113 and not legacycaller
8114 and not stringifier
8116 raise WebIDLError(
8117 "Identifier required for non-special methods",
8118 [self.getLocation(p, 2)],
8121 location = BuiltinLocation("<auto-generated-identifier>")
8122 identifier = IDLUnresolvedIdentifier(
8123 location,
8124 "__%s%s%s%s%s%s"
8126 "named"
8127 if specialType == IDLMethod.NamedOrIndexed.Named
8128 else "indexed"
8129 if specialType == IDLMethod.NamedOrIndexed.Indexed
8130 else "",
8131 "getter" if getter else "",
8132 "setter" if setter else "",
8133 "deleter" if deleter else "",
8134 "legacycaller" if legacycaller else "",
8135 "stringifier" if stringifier else "",
8137 allowDoubleUnderscore=True,
8140 method = IDLMethod(
8141 self.getLocation(p, 2),
8142 identifier,
8143 returnType,
8144 arguments,
8145 static=static,
8146 getter=getter,
8147 setter=setter,
8148 deleter=deleter,
8149 specialType=specialType,
8150 legacycaller=legacycaller,
8151 stringifier=stringifier,
8153 p[0] = method
8155 def p_Stringifier(self, p):
8157 Operation : STRINGIFIER SEMICOLON
8159 identifier = IDLUnresolvedIdentifier(
8160 BuiltinLocation("<auto-generated-identifier>"),
8161 "__stringifier",
8162 allowDoubleUnderscore=True,
8164 method = IDLMethod(
8165 self.getLocation(p, 1),
8166 identifier,
8167 returnType=BuiltinTypes[IDLBuiltinType.Types.domstring],
8168 arguments=[],
8169 stringifier=True,
8171 p[0] = method
8173 def p_QualifierStatic(self, p):
8175 Qualifier : STATIC
8177 p[0] = [IDLInterfaceMember.Special.Static]
8179 def p_QualifierStringifier(self, p):
8181 Qualifier : STRINGIFIER
8183 p[0] = [IDLInterfaceMember.Special.Stringifier]
8185 def p_Qualifiers(self, p):
8187 Qualifiers : Qualifier
8188 | Specials
8190 p[0] = p[1]
8192 def p_Specials(self, p):
8194 Specials : Special Specials
8196 p[0] = [p[1]]
8197 p[0].extend(p[2])
8199 def p_SpecialsEmpty(self, p):
8201 Specials :
8203 p[0] = []
8205 def p_SpecialGetter(self, p):
8207 Special : GETTER
8209 p[0] = IDLMethod.Special.Getter
8211 def p_SpecialSetter(self, p):
8213 Special : SETTER
8215 p[0] = IDLMethod.Special.Setter
8217 def p_SpecialDeleter(self, p):
8219 Special : DELETER
8221 p[0] = IDLMethod.Special.Deleter
8223 def p_SpecialLegacyCaller(self, p):
8225 Special : LEGACYCALLER
8227 p[0] = IDLMethod.Special.LegacyCaller
8229 def p_OperationRest(self, p):
8231 OperationRest : Type OptionalIdentifier LPAREN ArgumentList RPAREN SEMICOLON
8233 p[0] = (p[1], p[2], p[4])
8235 def p_OptionalIdentifier(self, p):
8237 OptionalIdentifier : IDENTIFIER
8239 p[0] = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1])
8241 def p_OptionalIdentifierEmpty(self, p):
8243 OptionalIdentifier :
8245 pass
8247 def p_ArgumentList(self, p):
8249 ArgumentList : Argument Arguments
8251 p[0] = [p[1]] if p[1] else []
8252 p[0].extend(p[2])
8254 def p_ArgumentListEmpty(self, p):
8256 ArgumentList :
8258 p[0] = []
8260 def p_Arguments(self, p):
8262 Arguments : COMMA Argument Arguments
8264 p[0] = [p[2]] if p[2] else []
8265 p[0].extend(p[3])
8267 def p_ArgumentsEmpty(self, p):
8269 Arguments :
8271 p[0] = []
8273 def p_Argument(self, p):
8275 Argument : ExtendedAttributeList ArgumentRest
8277 p[0] = p[2]
8278 p[0].addExtendedAttributes(p[1])
8280 def p_ArgumentRestOptional(self, p):
8282 ArgumentRest : OPTIONAL TypeWithExtendedAttributes ArgumentName Default
8284 t = p[2]
8285 assert isinstance(t, IDLType)
8286 # Arg names can be reserved identifiers
8287 identifier = IDLUnresolvedIdentifier(
8288 self.getLocation(p, 3), p[3], allowForbidden=True
8291 defaultValue = p[4]
8293 # We can't test t.isAny() here and give it a default value as needed,
8294 # since at this point t is not a fully resolved type yet (e.g. it might
8295 # be a typedef). We'll handle the 'any' case in IDLArgument.complete.
8297 p[0] = IDLArgument(
8298 self.getLocation(p, 3), identifier, t, True, defaultValue, False
8301 def p_ArgumentRest(self, p):
8303 ArgumentRest : Type Ellipsis ArgumentName
8305 t = p[1]
8306 assert isinstance(t, IDLType)
8307 # Arg names can be reserved identifiers
8308 identifier = IDLUnresolvedIdentifier(
8309 self.getLocation(p, 3), p[3], allowForbidden=True
8312 variadic = p[2]
8314 # We can't test t.isAny() here and give it a default value as needed,
8315 # since at this point t is not a fully resolved type yet (e.g. it might
8316 # be a typedef). We'll handle the 'any' case in IDLArgument.complete.
8318 # variadic implies optional
8319 # Any attributes that precede this may apply to the type, so
8320 # we configure the argument to forward type attributes down instead of producing
8321 # a parse error
8322 p[0] = IDLArgument(
8323 self.getLocation(p, 3),
8324 identifier,
8326 variadic,
8327 None,
8328 variadic,
8329 allowTypeAttributes=True,
8332 def p_ArgumentName(self, p):
8334 ArgumentName : IDENTIFIER
8335 | ArgumentNameKeyword
8337 p[0] = p[1]
8339 def p_ArgumentNameKeyword(self, p):
8341 ArgumentNameKeyword : ASYNC
8342 | ATTRIBUTE
8343 | CALLBACK
8344 | CONST
8345 | CONSTRUCTOR
8346 | DELETER
8347 | DICTIONARY
8348 | ENUM
8349 | EXCEPTION
8350 | GETTER
8351 | INCLUDES
8352 | INHERIT
8353 | INTERFACE
8354 | ITERABLE
8355 | LEGACYCALLER
8356 | MAPLIKE
8357 | MIXIN
8358 | NAMESPACE
8359 | PARTIAL
8360 | READONLY
8361 | REQUIRED
8362 | SERIALIZER
8363 | SETLIKE
8364 | SETTER
8365 | STATIC
8366 | STRINGIFIER
8367 | TYPEDEF
8368 | UNRESTRICTED
8370 p[0] = p[1]
8372 def p_AttributeName(self, p):
8374 AttributeName : IDENTIFIER
8375 | AttributeNameKeyword
8377 p[0] = p[1]
8379 def p_AttributeNameKeyword(self, p):
8381 AttributeNameKeyword : ASYNC
8382 | REQUIRED
8384 p[0] = p[1]
8386 def p_Ellipsis(self, p):
8388 Ellipsis : ELLIPSIS
8390 p[0] = True
8392 def p_EllipsisEmpty(self, p):
8394 Ellipsis :
8396 p[0] = False
8398 def p_ExceptionMember(self, p):
8400 ExceptionMember : Const
8401 | ExceptionField
8403 pass
8405 def p_ExceptionField(self, p):
8407 ExceptionField : Type IDENTIFIER SEMICOLON
8409 pass
8411 def p_ExtendedAttributeList(self, p):
8413 ExtendedAttributeList : LBRACKET ExtendedAttribute ExtendedAttributes RBRACKET
8415 p[0] = [p[2]]
8416 if p[3]:
8417 p[0].extend(p[3])
8419 def p_ExtendedAttributeListEmpty(self, p):
8421 ExtendedAttributeList :
8423 p[0] = []
8425 def p_ExtendedAttribute(self, p):
8427 ExtendedAttribute : ExtendedAttributeNoArgs
8428 | ExtendedAttributeArgList
8429 | ExtendedAttributeIdent
8430 | ExtendedAttributeWildcard
8431 | ExtendedAttributeNamedArgList
8432 | ExtendedAttributeIdentList
8434 p[0] = IDLExtendedAttribute(self.getLocation(p, 1), p[1])
8436 def p_ExtendedAttributeEmpty(self, p):
8438 ExtendedAttribute :
8440 pass
8442 def p_ExtendedAttributes(self, p):
8444 ExtendedAttributes : COMMA ExtendedAttribute ExtendedAttributes
8446 p[0] = [p[2]] if p[2] else []
8447 p[0].extend(p[3])
8449 def p_ExtendedAttributesEmpty(self, p):
8451 ExtendedAttributes :
8453 p[0] = []
8455 def p_Other(self, p):
8457 Other : INTEGER
8458 | FLOATLITERAL
8459 | IDENTIFIER
8460 | STRING
8461 | OTHER
8462 | ELLIPSIS
8463 | COLON
8464 | SCOPE
8465 | SEMICOLON
8466 | LT
8467 | EQUALS
8468 | GT
8469 | QUESTIONMARK
8470 | ASTERISK
8471 | DOMSTRING
8472 | BYTESTRING
8473 | USVSTRING
8474 | UTF8STRING
8475 | JSSTRING
8476 | PROMISE
8477 | ANY
8478 | BOOLEAN
8479 | BYTE
8480 | DOUBLE
8481 | FALSE
8482 | FLOAT
8483 | LONG
8484 | NULL
8485 | OBJECT
8486 | OCTET
8487 | OR
8488 | OPTIONAL
8489 | RECORD
8490 | SEQUENCE
8491 | SHORT
8492 | SYMBOL
8493 | TRUE
8494 | UNSIGNED
8495 | UNDEFINED
8496 | ArgumentNameKeyword
8498 pass
8500 def p_OtherOrComma(self, p):
8502 OtherOrComma : Other
8503 | COMMA
8505 pass
8507 def p_TypeSingleType(self, p):
8509 Type : SingleType
8511 p[0] = p[1]
8513 def p_TypeUnionType(self, p):
8515 Type : UnionType Null
8517 p[0] = self.handleNullable(p[1], p[2])
8519 def p_TypeWithExtendedAttributes(self, p):
8521 TypeWithExtendedAttributes : ExtendedAttributeList Type
8523 p[0] = p[2].withExtendedAttributes(p[1])
8525 def p_SingleTypeDistinguishableType(self, p):
8527 SingleType : DistinguishableType
8529 p[0] = p[1]
8531 def p_SingleTypeAnyType(self, p):
8533 SingleType : ANY
8535 p[0] = BuiltinTypes[IDLBuiltinType.Types.any]
8537 def p_SingleTypePromiseType(self, p):
8539 SingleType : PROMISE LT Type GT
8541 p[0] = IDLPromiseType(self.getLocation(p, 1), p[3])
8543 def p_UnionType(self, p):
8545 UnionType : LPAREN UnionMemberType OR UnionMemberType UnionMemberTypes RPAREN
8547 types = [p[2], p[4]]
8548 types.extend(p[5])
8549 p[0] = IDLUnionType(self.getLocation(p, 1), types)
8551 def p_UnionMemberTypeDistinguishableType(self, p):
8553 UnionMemberType : ExtendedAttributeList DistinguishableType
8555 p[0] = p[2].withExtendedAttributes(p[1])
8557 def p_UnionMemberType(self, p):
8559 UnionMemberType : UnionType Null
8561 p[0] = self.handleNullable(p[1], p[2])
8563 def p_UnionMemberTypes(self, p):
8565 UnionMemberTypes : OR UnionMemberType UnionMemberTypes
8567 p[0] = [p[2]]
8568 p[0].extend(p[3])
8570 def p_UnionMemberTypesEmpty(self, p):
8572 UnionMemberTypes :
8574 p[0] = []
8576 def p_DistinguishableType(self, p):
8578 DistinguishableType : PrimitiveType Null
8579 | ARRAYBUFFER Null
8580 | OBJECT Null
8581 | UNDEFINED Null
8583 if p[1] == "object":
8584 type = BuiltinTypes[IDLBuiltinType.Types.object]
8585 elif p[1] == "ArrayBuffer":
8586 type = BuiltinTypes[IDLBuiltinType.Types.ArrayBuffer]
8587 elif p[1] == "undefined":
8588 type = BuiltinTypes[IDLBuiltinType.Types.undefined]
8589 else:
8590 type = BuiltinTypes[p[1]]
8592 p[0] = self.handleNullable(type, p[2])
8594 def p_DistinguishableTypeStringType(self, p):
8596 DistinguishableType : StringType Null
8598 p[0] = self.handleNullable(p[1], p[2])
8600 def p_DistinguishableTypeSequenceType(self, p):
8602 DistinguishableType : SEQUENCE LT TypeWithExtendedAttributes GT Null
8604 innerType = p[3]
8605 type = IDLSequenceType(self.getLocation(p, 1), innerType)
8606 p[0] = self.handleNullable(type, p[5])
8608 def p_DistinguishableTypeRecordType(self, p):
8610 DistinguishableType : RECORD LT StringType COMMA TypeWithExtendedAttributes GT Null
8612 keyType = p[3]
8613 valueType = p[5]
8614 type = IDLRecordType(self.getLocation(p, 1), keyType, valueType)
8615 p[0] = self.handleNullable(type, p[7])
8617 def p_DistinguishableTypeObservableArrayType(self, p):
8619 DistinguishableType : OBSERVABLEARRAY LT TypeWithExtendedAttributes GT Null
8621 innerType = p[3]
8622 type = IDLObservableArrayType(self.getLocation(p, 1), innerType)
8623 p[0] = self.handleNullable(type, p[5])
8625 def p_DistinguishableTypeScopedName(self, p):
8627 DistinguishableType : ScopedName Null
8629 assert isinstance(p[1], IDLUnresolvedIdentifier)
8631 if p[1].name == "Promise":
8632 raise WebIDLError(
8633 "Promise used without saying what it's " "parametrized over",
8634 [self.getLocation(p, 1)],
8637 type = None
8639 try:
8640 if self.globalScope()._lookupIdentifier(p[1]):
8641 obj = self.globalScope()._lookupIdentifier(p[1])
8642 assert not obj.isType()
8643 if obj.isTypedef():
8644 type = IDLTypedefType(
8645 self.getLocation(p, 1), obj.innerType, obj.identifier.name
8647 elif obj.isCallback() and not obj.isInterface():
8648 type = IDLCallbackType(self.getLocation(p, 1), obj)
8649 else:
8650 type = IDLWrapperType(self.getLocation(p, 1), p[1])
8651 p[0] = self.handleNullable(type, p[2])
8652 return
8653 except Exception:
8654 pass
8656 type = IDLUnresolvedType(self.getLocation(p, 1), p[1])
8657 p[0] = self.handleNullable(type, p[2])
8659 def p_ConstType(self, p):
8661 ConstType : PrimitiveType
8663 p[0] = BuiltinTypes[p[1]]
8665 def p_ConstTypeIdentifier(self, p):
8667 ConstType : IDENTIFIER
8669 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1])
8671 p[0] = IDLUnresolvedType(self.getLocation(p, 1), identifier)
8673 def p_PrimitiveTypeUint(self, p):
8675 PrimitiveType : UnsignedIntegerType
8677 p[0] = p[1]
8679 def p_PrimitiveTypeBoolean(self, p):
8681 PrimitiveType : BOOLEAN
8683 p[0] = IDLBuiltinType.Types.boolean
8685 def p_PrimitiveTypeByte(self, p):
8687 PrimitiveType : BYTE
8689 p[0] = IDLBuiltinType.Types.byte
8691 def p_PrimitiveTypeOctet(self, p):
8693 PrimitiveType : OCTET
8695 p[0] = IDLBuiltinType.Types.octet
8697 def p_PrimitiveTypeFloat(self, p):
8699 PrimitiveType : FLOAT
8701 p[0] = IDLBuiltinType.Types.float
8703 def p_PrimitiveTypeUnrestictedFloat(self, p):
8705 PrimitiveType : UNRESTRICTED FLOAT
8707 p[0] = IDLBuiltinType.Types.unrestricted_float
8709 def p_PrimitiveTypeDouble(self, p):
8711 PrimitiveType : DOUBLE
8713 p[0] = IDLBuiltinType.Types.double
8715 def p_PrimitiveTypeUnrestictedDouble(self, p):
8717 PrimitiveType : UNRESTRICTED DOUBLE
8719 p[0] = IDLBuiltinType.Types.unrestricted_double
8721 def p_StringType(self, p):
8723 StringType : BuiltinStringType
8725 p[0] = BuiltinTypes[p[1]]
8727 def p_BuiltinStringTypeDOMString(self, p):
8729 BuiltinStringType : DOMSTRING
8731 p[0] = IDLBuiltinType.Types.domstring
8733 def p_BuiltinStringTypeBytestring(self, p):
8735 BuiltinStringType : BYTESTRING
8737 p[0] = IDLBuiltinType.Types.bytestring
8739 def p_BuiltinStringTypeUSVString(self, p):
8741 BuiltinStringType : USVSTRING
8743 p[0] = IDLBuiltinType.Types.usvstring
8745 def p_BuiltinStringTypeUTF8String(self, p):
8747 BuiltinStringType : UTF8STRING
8749 p[0] = IDLBuiltinType.Types.utf8string
8751 def p_BuiltinStringTypeJSString(self, p):
8753 BuiltinStringType : JSSTRING
8755 p[0] = IDLBuiltinType.Types.jsstring
8757 def p_UnsignedIntegerTypeUnsigned(self, p):
8759 UnsignedIntegerType : UNSIGNED IntegerType
8761 # Adding one to a given signed integer type gets you the unsigned type:
8762 p[0] = p[2] + 1
8764 def p_UnsignedIntegerType(self, p):
8766 UnsignedIntegerType : IntegerType
8768 p[0] = p[1]
8770 def p_IntegerTypeShort(self, p):
8772 IntegerType : SHORT
8774 p[0] = IDLBuiltinType.Types.short
8776 def p_IntegerTypeLong(self, p):
8778 IntegerType : LONG OptionalLong
8780 if p[2]:
8781 p[0] = IDLBuiltinType.Types.long_long
8782 else:
8783 p[0] = IDLBuiltinType.Types.long
8785 def p_OptionalLong(self, p):
8787 OptionalLong : LONG
8789 p[0] = True
8791 def p_OptionalLongEmpty(self, p):
8793 OptionalLong :
8795 p[0] = False
8797 def p_Null(self, p):
8799 Null : QUESTIONMARK
8802 if len(p) > 1:
8803 p[0] = self.getLocation(p, 1)
8804 else:
8805 p[0] = None
8807 def p_ScopedName(self, p):
8809 ScopedName : AbsoluteScopedName
8810 | RelativeScopedName
8812 p[0] = p[1]
8814 def p_AbsoluteScopedName(self, p):
8816 AbsoluteScopedName : SCOPE IDENTIFIER ScopedNameParts
8818 assert False
8819 pass
8821 def p_RelativeScopedName(self, p):
8823 RelativeScopedName : IDENTIFIER ScopedNameParts
8825 assert not p[2] # Not implemented!
8827 p[0] = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1])
8829 def p_ScopedNameParts(self, p):
8831 ScopedNameParts : SCOPE IDENTIFIER ScopedNameParts
8833 assert False
8834 pass
8836 def p_ScopedNamePartsEmpty(self, p):
8838 ScopedNameParts :
8840 p[0] = None
8842 def p_ExtendedAttributeNoArgs(self, p):
8844 ExtendedAttributeNoArgs : IDENTIFIER
8846 p[0] = (p[1],)
8848 def p_ExtendedAttributeArgList(self, p):
8850 ExtendedAttributeArgList : IDENTIFIER LPAREN ArgumentList RPAREN
8852 p[0] = (p[1], p[3])
8854 def p_ExtendedAttributeIdent(self, p):
8856 ExtendedAttributeIdent : IDENTIFIER EQUALS STRING
8857 | IDENTIFIER EQUALS IDENTIFIER
8859 p[0] = (p[1], p[3])
8861 def p_ExtendedAttributeWildcard(self, p):
8863 ExtendedAttributeWildcard : IDENTIFIER EQUALS ASTERISK
8865 p[0] = (p[1], p[3])
8867 def p_ExtendedAttributeNamedArgList(self, p):
8869 ExtendedAttributeNamedArgList : IDENTIFIER EQUALS IDENTIFIER LPAREN ArgumentList RPAREN
8871 p[0] = (p[1], p[3], p[5])
8873 def p_ExtendedAttributeIdentList(self, p):
8875 ExtendedAttributeIdentList : IDENTIFIER EQUALS LPAREN IdentifierList RPAREN
8877 p[0] = (p[1], p[4])
8879 def p_IdentifierList(self, p):
8881 IdentifierList : IDENTIFIER Identifiers
8883 idents = list(p[2])
8884 # This is only used for identifier-list-valued extended attributes, and if
8885 # we're going to restrict to IDENTIFIER here we should at least allow
8886 # escaping with leading '_' as usual for identifiers.
8887 ident = p[1]
8888 if ident[0] == "_":
8889 ident = ident[1:]
8890 idents.insert(0, ident)
8891 p[0] = idents
8893 def p_IdentifiersList(self, p):
8895 Identifiers : COMMA IDENTIFIER Identifiers
8897 idents = list(p[3])
8898 # This is only used for identifier-list-valued extended attributes, and if
8899 # we're going to restrict to IDENTIFIER here we should at least allow
8900 # escaping with leading '_' as usual for identifiers.
8901 ident = p[2]
8902 if ident[0] == "_":
8903 ident = ident[1:]
8904 idents.insert(0, ident)
8905 p[0] = idents
8907 def p_IdentifiersEmpty(self, p):
8909 Identifiers :
8911 p[0] = []
8913 def p_error(self, p):
8914 if not p:
8915 raise WebIDLError(
8917 "Syntax Error at end of file. Possibly due to "
8918 "missing semicolon(;), braces(}) or both"
8920 [self._filename],
8922 else:
8923 raise WebIDLError(
8924 "invalid syntax",
8925 [Location(self.lexer, p.lineno, p.lexpos, self._filename)],
8928 def __init__(self, outputdir="", lexer=None):
8929 Tokenizer.__init__(self, outputdir, lexer)
8931 logger = SqueakyCleanLogger()
8932 try:
8933 self.parser = yacc.yacc(
8934 module=self,
8935 outputdir=outputdir,
8936 errorlog=logger,
8937 write_tables=False,
8938 # Pickling the grammar is a speedup in
8939 # some cases (older Python?) but a
8940 # significant slowdown in others.
8941 # We're not pickling for now, until it
8942 # becomes a speedup again.
8943 # , picklefile='WebIDLGrammar.pkl'
8945 finally:
8946 logger.reportGrammarErrors()
8948 self._globalScope = IDLScope(BuiltinLocation("<Global Scope>"), None, None)
8949 self._installBuiltins(self._globalScope)
8950 self._productions = []
8952 self._filename = "<builtin>"
8953 self.lexer.input(Parser._builtins)
8954 self._filename = None
8956 self.parser.parse(lexer=self.lexer, tracking=True)
8958 def _installBuiltins(self, scope):
8959 assert isinstance(scope, IDLScope)
8961 # range omits the last value.
8962 for x in range(
8963 IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1
8965 builtin = BuiltinTypes[x]
8966 name = builtin.name
8967 IDLTypedef(BuiltinLocation("<builtin type>"), scope, builtin, name)
8969 @staticmethod
8970 def handleNullable(type, questionMarkLocation):
8971 if questionMarkLocation is not None:
8972 type = IDLNullableType(questionMarkLocation, type)
8974 return type
8976 def parse(self, t, filename=None):
8977 self.lexer.input(t)
8979 # for tok in iter(self.lexer.token, None):
8980 # print tok
8982 self._filename = filename
8983 self._productions.extend(self.parser.parse(lexer=self.lexer, tracking=True))
8984 self._filename = None
8986 def finish(self):
8987 # If we have interfaces that are iterable, create their
8988 # iterator interfaces and add them to the productions array.
8989 interfaceStatements = []
8990 for p in self._productions:
8991 if isinstance(p, IDLInterface):
8992 interfaceStatements.append(p)
8994 for iface in interfaceStatements:
8995 iterable = None
8996 # We haven't run finish() on the interface yet, so we don't know
8997 # whether our interface is maplike/setlike/iterable or not. This
8998 # means we have to loop through the members to see if we have an
8999 # iterable member.
9000 for m in iface.members:
9001 if isinstance(m, (IDLIterable, IDLAsyncIterable)):
9002 iterable = m
9003 break
9004 if iterable and (iterable.isPairIterator() or iterable.isAsyncIterable()):
9006 def simpleExtendedAttr(str):
9007 return IDLExtendedAttribute(iface.location, (str,))
9009 if isinstance(iterable, IDLAsyncIterable):
9010 nextReturnType = IDLPromiseType(
9011 iterable.location, BuiltinTypes[IDLBuiltinType.Types.any]
9013 else:
9014 nextReturnType = BuiltinTypes[IDLBuiltinType.Types.object]
9015 nextMethod = IDLMethod(
9016 iterable.location,
9017 IDLUnresolvedIdentifier(iterable.location, "next"),
9018 nextReturnType,
9021 nextMethod.addExtendedAttributes([simpleExtendedAttr("Throws")])
9023 methods = [nextMethod]
9025 if iterable.getExtendedAttribute("GenerateReturnMethod"):
9026 assert isinstance(iterable, IDLAsyncIterable)
9028 returnMethod = IDLMethod(
9029 iterable.location,
9030 IDLUnresolvedIdentifier(iterable.location, "return"),
9031 IDLPromiseType(
9032 iterable.location, BuiltinTypes[IDLBuiltinType.Types.any]
9035 IDLArgument(
9036 iterable.location,
9037 IDLUnresolvedIdentifier(
9038 BuiltinLocation("<auto-generated-identifier>"),
9039 "value",
9041 BuiltinTypes[IDLBuiltinType.Types.any],
9042 optional=True,
9046 returnMethod.addExtendedAttributes([simpleExtendedAttr("Throws")])
9047 methods.append(returnMethod)
9049 if iterable.isIterable():
9050 itr_suffix = "Iterator"
9051 else:
9052 itr_suffix = "AsyncIterator"
9053 itr_ident = IDLUnresolvedIdentifier(
9054 iface.location, iface.identifier.name + itr_suffix
9056 if iterable.isIterable():
9057 classNameOverride = iface.identifier.name + " Iterator"
9058 elif iterable.isAsyncIterable():
9059 classNameOverride = iface.identifier.name + " AsyncIterator"
9060 itr_iface = IDLInterface(
9061 iface.location,
9062 self.globalScope(),
9063 itr_ident,
9064 None,
9065 methods,
9066 isKnownNonPartial=True,
9067 classNameOverride=classNameOverride,
9069 itr_iface.addExtendedAttributes(
9070 [simpleExtendedAttr("LegacyNoInterfaceObject")]
9072 # Make sure the exposure set for the iterator interface is the
9073 # same as the exposure set for the iterable interface, because
9074 # we're going to generate methods on the iterable that return
9075 # instances of the iterator.
9076 itr_iface._exposureGlobalNames = set(iface._exposureGlobalNames)
9077 # Always append generated iterable interfaces after the
9078 # interface they're a member of, otherwise nativeType generation
9079 # won't work correctly.
9080 if iterable.isIterable():
9081 itr_iface.iterableInterface = iface
9082 else:
9083 itr_iface.asyncIterableInterface = iface
9084 self._productions.append(itr_iface)
9085 iterable.iteratorType = IDLWrapperType(iface.location, itr_iface)
9087 # Make sure we finish IDLIncludesStatements before we finish the
9088 # IDLInterfaces.
9089 # XXX khuey hates this bit and wants to nuke it from orbit.
9090 includesStatements = [
9091 p for p in self._productions if isinstance(p, IDLIncludesStatement)
9093 otherStatements = [
9094 p for p in self._productions if not isinstance(p, IDLIncludesStatement)
9096 for production in includesStatements:
9097 production.finish(self.globalScope())
9098 for production in otherStatements:
9099 production.finish(self.globalScope())
9101 # Do any post-finish validation we need to do
9102 for production in self._productions:
9103 production.validate()
9105 # De-duplicate self._productions, without modifying its order.
9106 seen = set()
9107 result = []
9108 for p in self._productions:
9109 if p not in seen:
9110 seen.add(p)
9111 result.append(p)
9112 return result
9114 def reset(self):
9115 return Parser(lexer=self.lexer)
9117 # Builtin IDL defined by WebIDL
9118 _builtins = """
9119 typedef (ArrayBufferView or ArrayBuffer) BufferSource;
9123 def main():
9124 # Parse arguments.
9125 from optparse import OptionParser
9127 usageString = "usage: %prog [options] files"
9128 o = OptionParser(usage=usageString)
9129 o.add_option(
9130 "--cachedir",
9131 dest="cachedir",
9132 default=None,
9133 help="Directory in which to cache lex/parse tables.",
9135 o.add_option(
9136 "--verbose-errors",
9137 action="store_true",
9138 default=False,
9139 help="When an error happens, display the Python traceback.",
9141 (options, args) = o.parse_args()
9143 if len(args) < 1:
9144 o.error(usageString)
9146 fileList = args
9147 baseDir = os.getcwd()
9149 # Parse the WebIDL.
9150 parser = Parser(options.cachedir)
9151 try:
9152 for filename in fileList:
9153 fullPath = os.path.normpath(os.path.join(baseDir, filename))
9154 f = open(fullPath, "rb")
9155 lines = f.readlines()
9156 f.close()
9157 print(fullPath)
9158 parser.parse("".join(lines), fullPath)
9159 parser.finish()
9160 except WebIDLError as e:
9161 if options.verbose_errors:
9162 traceback.print_exc()
9163 else:
9164 print(e)
9167 if __name__ == "__main__":
9168 main()