Bug 1935611 - Fix libyuv/libpng link failed for loongarch64. r=glandium,tnikkel,ng
[gecko.git] / dom / bindings / parser / WebIDL.py
blob4d4b55081b9e8583d19cee1f80704a3527ff3434
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 # This is surprisingly faster than using the enum.IntEnum type (which doesn't
47 # support 'base' anyway)
48 def enum(*names, base=None):
49 if base is not None:
50 names = base.attrs + names
52 class CustomEnumType(object):
53 attrs = names
55 def __setattr__(self, name, value): # this makes it read-only
56 raise NotImplementedError
58 for v, k in enumerate(names):
59 setattr(CustomEnumType, k, v)
61 return CustomEnumType()
64 class WebIDLError(Exception):
65 def __init__(self, message, locations, warning=False):
66 self.message = message
67 self.locations = [str(loc) for loc in locations]
68 self.warning = warning
70 def __str__(self):
71 return "%s: %s%s%s" % (
72 self.warning and "warning" or "error",
73 self.message,
74 ", " if len(self.locations) != 0 else "",
75 "\n".join(self.locations),
79 class Location(object):
80 def __init__(self, lexer, lineno, lexpos, filename):
81 self._line = None
82 self._lineno = lineno
83 self._lexpos = lexpos
84 self._lexdata = lexer.lexdata
85 self.filename = filename if filename else "<unknown>"
87 def __eq__(self, other):
88 return self._lexpos == other._lexpos and self.filename == other.filename
90 def resolve(self):
91 if self._line:
92 return
94 startofline = self._lexdata.rfind("\n", 0, self._lexpos) + 1
95 endofline = self._lexdata.find("\n", self._lexpos, self._lexpos + 80)
96 if endofline != -1:
97 self._line = self._lexdata[startofline:endofline]
98 else:
99 self._line = self._lexdata[startofline:]
100 self._colno = self._lexpos - startofline
102 # Our line number seems to point to the start of self._lexdata
103 self._lineno += self._lexdata.count("\n", 0, startofline)
105 def get(self):
106 self.resolve()
107 return "%s line %s:%s" % (self.filename, self._lineno, self._colno)
109 def _pointerline(self):
110 return " " * self._colno + "^"
112 def __str__(self):
113 self.resolve()
114 return "%s line %s:%s\n%s\n%s" % (
115 self.filename,
116 self._lineno,
117 self._colno,
118 self._line,
119 self._pointerline(),
123 class BuiltinLocation(object):
124 __slots__ = "msg", "filename"
126 def __init__(self, text):
127 self.msg = text + "\n"
128 self.filename = "<builtin>"
130 def __eq__(self, other):
131 return isinstance(other, BuiltinLocation) and self.msg == other.msg
133 def resolve(self):
134 pass
136 def get(self):
137 return self.msg
139 def __str__(self):
140 return self.get()
143 # Data Model
146 class IDLObject(object):
147 __slots__ = "location", "userData", "filename"
149 def __init__(self, location):
150 self.location = location
151 self.userData = {}
152 self.filename = location and location.filename
154 def isInterface(self):
155 return False
157 def isNamespace(self):
158 return False
160 def isInterfaceMixin(self):
161 return False
163 def isEnum(self):
164 return False
166 def isCallback(self):
167 return False
169 def isType(self):
170 return False
172 def isDictionary(self):
173 return False
175 def isUnion(self):
176 return False
178 def isTypedef(self):
179 return False
181 def getUserData(self, key, default):
182 return self.userData.get(key, default)
184 def setUserData(self, key, value):
185 self.userData[key] = value
187 def addExtendedAttributes(self, attrs):
188 assert False # Override me!
190 def handleExtendedAttribute(self, attr):
191 assert False # Override me!
193 def _getDependentObjects(self):
194 assert False # Override me!
196 def getDeps(self, visited=None):
197 """Return a set of files that this object depends on. If any of
198 these files are changed the parser needs to be rerun to regenerate
199 a new IDLObject.
201 The visited argument is a set of all the objects already visited.
202 We must test to see if we are in it, and if so, do nothing. This
203 prevents infinite recursion."""
205 # NB: We can't use visited=set() above because the default value is
206 # evaluated when the def statement is evaluated, not when the function
207 # is executed, so there would be one set for all invocations.
208 if visited is None:
209 visited = set()
211 if self in visited:
212 return set()
214 visited.add(self)
216 deps = set()
217 if self.filename != "<builtin>":
218 deps.add(self.filename)
220 for d in self._getDependentObjects():
221 deps.update(d.getDeps(visited))
223 return deps
226 class IDLScope(IDLObject):
227 __slots__ = "parentScope", "_name", "_dict", "globalNames", "globalNameMapping"
229 def __init__(self, location, parentScope, identifier):
230 IDLObject.__init__(self, location)
232 self.parentScope = parentScope
233 if identifier:
234 assert isinstance(identifier, IDLIdentifier)
235 self._name = identifier
236 else:
237 self._name = None
239 self._dict = {}
240 self.globalNames = set()
241 # A mapping from global name to the set of global interfaces
242 # that have that global name.
243 self.globalNameMapping = defaultdict(set)
245 def __str__(self):
246 return self.QName()
248 def QName(self):
249 # It's possible for us to be called before __init__ has been called, for
250 # the IDLObjectWithScope case. In that case, self._name won't be set yet.
251 if hasattr(self, "_name"):
252 name = self._name
253 else:
254 name = None
255 if name:
256 return name.QName() + "::"
257 return "::"
259 def ensureUnique(self, identifier, object):
261 Ensure that there is at most one 'identifier' in scope ('self').
262 Note that object can be None. This occurs if we end up here for an
263 interface type we haven't seen yet.
265 assert isinstance(identifier, IDLUnresolvedIdentifier)
266 assert not object or isinstance(object, IDLObjectWithIdentifier)
267 assert not object or object.identifier == identifier
269 if identifier.name in self._dict:
270 if not object:
271 return
273 # ensureUnique twice with the same object is not allowed
274 assert id(object) != id(self._dict[identifier.name])
276 replacement = self.resolveIdentifierConflict(
277 self, identifier, self._dict[identifier.name], object
279 self._dict[identifier.name] = replacement
280 return
282 self.addNewIdentifier(identifier, object)
284 def addNewIdentifier(self, identifier, object):
285 assert object
287 self._dict[identifier.name] = object
289 def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject):
290 if (
291 isinstance(originalObject, IDLExternalInterface)
292 and isinstance(newObject, IDLExternalInterface)
293 and originalObject.identifier.name == newObject.identifier.name
295 return originalObject
297 if isinstance(originalObject, IDLExternalInterface) or isinstance(
298 newObject, IDLExternalInterface
300 raise WebIDLError(
301 "Name collision between "
302 "interface declarations for identifier '%s' at '%s' and '%s'"
303 % (identifier.name, originalObject.location, newObject.location),
307 if isinstance(originalObject, IDLDictionary) or isinstance(
308 newObject, IDLDictionary
310 raise WebIDLError(
311 "Name collision between dictionary declarations for "
312 "identifier '%s'.\n%s\n%s"
313 % (identifier.name, originalObject.location, newObject.location),
317 # We do the merging of overloads here as opposed to in IDLInterface
318 # because we need to merge overloads of LegacyFactoryFunctions and we need to
319 # detect conflicts in those across interfaces. See also the comment in
320 # IDLInterface.addExtendedAttributes for "LegacyFactoryFunction".
321 if isinstance(originalObject, IDLMethod) and isinstance(newObject, IDLMethod):
322 return originalObject.addOverload(newObject)
324 # Default to throwing, derived classes can override.
325 raise self.createIdentifierConflictError(identifier, originalObject, newObject)
327 def createIdentifierConflictError(self, identifier, originalObject, newObject):
328 conflictdesc = "\n\t%s at %s\n\t%s at %s" % (
329 originalObject,
330 originalObject.location,
331 newObject,
332 newObject.location,
335 return WebIDLError(
336 "Multiple unresolvable definitions of identifier '%s' in scope '%s'%s"
337 % (identifier.name, str(self), conflictdesc),
341 def _lookupIdentifier(self, identifier):
342 return self._dict[identifier.name]
344 def lookupIdentifier(self, identifier):
345 assert isinstance(identifier, IDLIdentifier)
346 assert identifier.scope == self
347 return self._lookupIdentifier(identifier)
349 def addIfaceGlobalNames(self, interfaceName, globalNames):
350 """Record the global names (from |globalNames|) that can be used in
351 [Exposed] to expose things in a global named |interfaceName|"""
352 self.globalNames.update(globalNames)
353 for name in globalNames:
354 self.globalNameMapping[name].add(interfaceName)
357 class IDLIdentifier(IDLObject):
358 __slots__ = "name", "scope"
360 def __init__(self, location, scope, name):
361 IDLObject.__init__(self, location)
363 self.name = name
364 assert isinstance(scope, IDLScope)
365 self.scope = scope
367 def __str__(self):
368 return self.QName()
370 def QName(self):
371 return self.scope.QName() + self.name
373 def __hash__(self):
374 return self.QName().__hash__()
376 def __eq__(self, other):
377 return self.QName() == other.QName()
379 def object(self):
380 return self.scope.lookupIdentifier(self)
383 class IDLUnresolvedIdentifier(IDLObject):
384 __slots__ = ("name",)
386 def __init__(
387 self, location, name, allowDoubleUnderscore=False, allowForbidden=False
389 IDLObject.__init__(self, location)
391 assert name
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 # no slots, incompatible with multiple inheritance
431 def __init__(self, location, parentScope, identifier):
432 IDLObject.__init__(self, location)
434 assert isinstance(identifier, IDLUnresolvedIdentifier)
436 self.identifier = identifier
438 if parentScope:
439 self.resolve(parentScope)
441 def resolve(self, parentScope):
442 assert isinstance(parentScope, IDLScope)
443 assert isinstance(self.identifier, IDLUnresolvedIdentifier)
444 self.identifier.resolve(parentScope, self)
447 class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope):
448 __slots__ = ()
450 def __init__(self, location, parentScope, identifier):
451 assert isinstance(identifier, IDLUnresolvedIdentifier)
453 IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
454 IDLScope.__init__(self, location, parentScope, self.identifier)
457 class IDLIdentifierPlaceholder(IDLObjectWithIdentifier):
458 __slots__ = ()
460 def __init__(self, location, identifier):
461 assert isinstance(identifier, IDLUnresolvedIdentifier)
462 IDLObjectWithIdentifier.__init__(self, location, None, identifier)
464 def finish(self, scope):
465 try:
466 scope._lookupIdentifier(self.identifier)
467 except Exception:
468 raise WebIDLError(
469 "Unresolved type '%s'." % self.identifier, [self.location]
472 obj = self.identifier.resolve(scope, None)
473 return scope.lookupIdentifier(obj)
476 class IDLExposureMixins:
477 # no slots, incompatible with multiple inheritance
478 def __init__(self, location):
479 # _exposureGlobalNames are the global names listed in our [Exposed]
480 # extended attribute. exposureSet is the exposure set as defined in the
481 # Web IDL spec: it contains interface names.
482 self._exposureGlobalNames = set()
483 self.exposureSet = set()
484 self._location = location
485 self._globalScope = None
487 def finish(self, scope):
488 assert scope.parentScope is None
489 self._globalScope = scope
491 if "*" in self._exposureGlobalNames:
492 self._exposureGlobalNames = scope.globalNames
493 else:
494 # Verify that our [Exposed] value, if any, makes sense.
495 for globalName in self._exposureGlobalNames:
496 if globalName not in scope.globalNames:
497 raise WebIDLError(
498 "Unknown [Exposed] value %s" % globalName, [self._location]
501 # Verify that we are exposed _somwhere_ if we have some place to be
502 # exposed. We don't want to assert that we're definitely exposed
503 # because a lot of our parser tests have small-enough IDL snippets that
504 # they don't include any globals, and we don't really want to go through
505 # and add global interfaces and [Exposed] annotations to all those
506 # tests.
507 if len(scope.globalNames) != 0 and len(self._exposureGlobalNames) == 0:
508 raise WebIDLError(
510 "'%s' is not exposed anywhere even though we have "
511 "globals to be exposed to"
513 % self,
514 [self.location],
517 globalNameSetToExposureSet(scope, self._exposureGlobalNames, self.exposureSet)
519 def isExposedInWindow(self):
520 return "Window" in self.exposureSet
522 def isExposedInAnyWorker(self):
523 return len(self.getWorkerExposureSet()) > 0
525 def isExposedInWorkerDebugger(self):
526 return len(self.getWorkerDebuggerExposureSet()) > 0
528 def isExposedInAnyWorklet(self):
529 return len(self.getWorkletExposureSet()) > 0
531 def isExposedInSomeButNotAllWorkers(self):
533 Returns true if the Exposed extended attribute for this interface
534 exposes it in some worker globals but not others. The return value does
535 not depend on whether the interface is exposed in Window or System
536 globals.
538 if not self.isExposedInAnyWorker():
539 return False
540 workerScopes = self.parentScope.globalNameMapping["Worker"]
541 return len(workerScopes.difference(self.exposureSet)) > 0
543 def isExposedInShadowRealms(self):
544 return "ShadowRealmGlobalScope" in self.exposureSet
546 def getWorkerExposureSet(self):
547 workerScopes = self._globalScope.globalNameMapping["Worker"]
548 return workerScopes.intersection(self.exposureSet)
550 def getWorkletExposureSet(self):
551 workletScopes = self._globalScope.globalNameMapping["Worklet"]
552 return workletScopes.intersection(self.exposureSet)
554 def getWorkerDebuggerExposureSet(self):
555 workerDebuggerScopes = self._globalScope.globalNameMapping["WorkerDebugger"]
556 return workerDebuggerScopes.intersection(self.exposureSet)
559 class IDLExternalInterface(IDLObjectWithIdentifier):
560 __slots__ = ("parent",)
562 def __init__(self, location, parentScope, identifier):
563 assert isinstance(identifier, IDLUnresolvedIdentifier)
564 assert isinstance(parentScope, IDLScope)
565 self.parent = None
566 IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
567 IDLObjectWithIdentifier.resolve(self, parentScope)
569 def finish(self, scope):
570 pass
572 def validate(self):
573 pass
575 def isIteratorInterface(self):
576 return False
578 def isAsyncIteratorInterface(self):
579 return False
581 def isExternal(self):
582 return True
584 def isInterface(self):
585 return True
587 def addExtendedAttributes(self, attrs):
588 if len(attrs) != 0:
589 raise WebIDLError(
590 "There are no extended attributes that are "
591 "allowed on external interfaces",
592 [attrs[0].location, self.location],
595 def resolve(self, parentScope):
596 pass
598 def getJSImplementation(self):
599 return None
601 def isJSImplemented(self):
602 return False
604 def hasProbablyShortLivingWrapper(self):
605 return False
607 def _getDependentObjects(self):
608 return set()
611 class IDLPartialDictionary(IDLObject):
612 __slots__ = "identifier", "members", "_nonPartialDictionary", "_finished"
614 def __init__(self, location, name, members, nonPartialDictionary):
615 assert isinstance(name, IDLUnresolvedIdentifier)
617 IDLObject.__init__(self, location)
618 self.identifier = name
619 self.members = members
620 self._nonPartialDictionary = nonPartialDictionary
621 self._finished = False
622 nonPartialDictionary.addPartialDictionary(self)
624 def addExtendedAttributes(self, attrs):
625 pass
627 def finish(self, scope):
628 if self._finished:
629 return
630 self._finished = True
632 # Need to make sure our non-partial dictionary gets
633 # finished so it can report cases when we only have partial
634 # dictionaries.
635 self._nonPartialDictionary.finish(scope)
637 def validate(self):
638 pass
641 class IDLPartialInterfaceOrNamespace(IDLObject):
642 __slots__ = (
643 "identifier",
644 "members",
645 "propagatedExtendedAttrs",
646 "_haveSecureContextExtendedAttribute",
647 "_nonPartialInterfaceOrNamespace",
648 "_finished",
651 def __init__(self, location, name, members, nonPartialInterfaceOrNamespace):
652 assert isinstance(name, IDLUnresolvedIdentifier)
654 IDLObject.__init__(self, location)
655 self.identifier = name
656 self.members = members
657 # propagatedExtendedAttrs are the ones that should get
658 # propagated to our non-partial interface.
659 self.propagatedExtendedAttrs = []
660 self._haveSecureContextExtendedAttribute = False
661 self._nonPartialInterfaceOrNamespace = nonPartialInterfaceOrNamespace
662 self._finished = False
663 nonPartialInterfaceOrNamespace.addPartial(self)
665 def addExtendedAttributes(self, attrs):
666 for attr in attrs:
667 identifier = attr.identifier()
669 if identifier == "LegacyFactoryFunction":
670 self.propagatedExtendedAttrs.append(attr)
671 elif identifier == "SecureContext":
672 self._haveSecureContextExtendedAttribute = True
673 # This gets propagated to all our members.
674 for member in self.members:
675 if member.getExtendedAttribute("SecureContext"):
676 typeName = self._nonPartialInterfaceOrNamespace.typeName()
677 raise WebIDLError(
678 "[SecureContext] specified on both a partial %s member "
679 "and on the partial %s itself" % (typeName, typeName),
680 [member.location, attr.location],
682 member.addExtendedAttributes([attr])
683 elif identifier == "Exposed":
684 # This just gets propagated to all our members.
685 for member in self.members:
686 if len(member._exposureGlobalNames) != 0:
687 typeName = self._nonPartialInterfaceOrNamespace.typeName()
688 raise WebIDLError(
689 "[Exposed] specified on both a partial %s member and "
690 "on the partial %s itself" % (typeName, typeName),
691 [member.location, attr.location],
693 member.addExtendedAttributes([attr])
694 else:
695 raise WebIDLError(
696 "Unknown extended attribute %s on partial %s"
697 % (identifier, self._nonPartialInterfaceOrNamespace.typeName()),
698 [attr.location],
701 def finish(self, scope):
702 if self._finished:
703 return
704 self._finished = True
705 if (
706 not self._haveSecureContextExtendedAttribute
707 and self._nonPartialInterfaceOrNamespace.getExtendedAttribute(
708 "SecureContext"
711 # This gets propagated to all our members.
712 for member in self.members:
713 if member.getExtendedAttribute("SecureContext"):
714 raise WebIDLError(
715 "[SecureContext] specified on both a "
716 "partial interface member and on the "
717 "non-partial interface",
719 member.location,
720 self._nonPartialInterfaceOrNamespace.location,
723 member.addExtendedAttributes(
725 IDLExtendedAttribute(
726 self._nonPartialInterfaceOrNamespace.location,
727 ("SecureContext",),
731 # Need to make sure our non-partial interface or namespace gets
732 # finished so it can report cases when we only have partial
733 # interfaces/namespaces.
734 self._nonPartialInterfaceOrNamespace.finish(scope)
736 def validate(self):
737 pass
740 def convertExposedAttrToGlobalNameSet(exposedAttr, targetSet):
741 assert len(targetSet) == 0
742 if exposedAttr.hasValue():
743 targetSet.add(exposedAttr.value())
744 else:
745 assert exposedAttr.hasArgs()
746 targetSet.update(exposedAttr.args())
749 def globalNameSetToExposureSet(globalScope, nameSet, exposureSet):
750 for name in nameSet:
751 exposureSet.update(globalScope.globalNameMapping[name])
754 # Because WebIDL allows static and regular operations with the same identifier
755 # we use a special class to be able to store them both in the scope for the
756 # same identifier.
757 class IDLOperations:
758 __slots__ = "static", "regular"
760 def __init__(self, static=None, regular=None):
761 self.static = static
762 self.regular = regular
765 class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMixins):
766 __slots__ = (
767 "_finished",
768 "members",
769 "_partials",
770 "_extendedAttrDict",
771 "_isKnownNonPartial",
774 def __init__(self, location, parentScope, name):
775 assert isinstance(parentScope, IDLScope)
776 assert isinstance(name, IDLUnresolvedIdentifier)
778 self._finished = False
779 self.members = []
780 self._partials = []
781 self._extendedAttrDict = {}
782 self._isKnownNonPartial = False
784 IDLObjectWithScope.__init__(self, location, parentScope, name)
785 IDLExposureMixins.__init__(self, location)
787 def finish(self, scope):
788 if not self._isKnownNonPartial:
789 raise WebIDLError(
790 "%s does not have a non-partial declaration" % str(self),
791 [self.location],
794 IDLExposureMixins.finish(self, scope)
796 # Now go ahead and merge in our partials.
797 for partial in self._partials:
798 partial.finish(scope)
799 self.addExtendedAttributes(partial.propagatedExtendedAttrs)
800 self.members.extend(partial.members)
802 def addNewIdentifier(self, identifier, object):
803 if isinstance(object, IDLMethod):
804 if object.isStatic():
805 object = IDLOperations(static=object)
806 else:
807 object = IDLOperations(regular=object)
809 IDLScope.addNewIdentifier(self, identifier, object)
811 def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject):
812 assert isinstance(scope, IDLScope)
813 assert isinstance(newObject, IDLInterfaceMember)
815 # The identifier of a regular operation or static operation must not be
816 # the same as the identifier of a constant or attribute.
817 if isinstance(newObject, IDLMethod) != isinstance(
818 originalObject, IDLOperations
820 if isinstance(originalObject, IDLOperations):
821 if originalObject.regular is not None:
822 originalObject = originalObject.regular
823 else:
824 assert originalObject.static is not None
825 originalObject = originalObject.static
827 raise self.createIdentifierConflictError(
828 identifier, originalObject, newObject
831 if isinstance(newObject, IDLMethod):
832 originalOperations = originalObject
833 if newObject.isStatic():
834 if originalOperations.static is None:
835 originalOperations.static = newObject
836 return originalOperations
838 originalObject = originalOperations.static
839 else:
840 if originalOperations.regular is None:
841 originalOperations.regular = newObject
842 return originalOperations
844 originalObject = originalOperations.regular
846 assert isinstance(originalObject, IDLMethod)
847 else:
848 assert isinstance(originalObject, IDLInterfaceMember)
850 retval = IDLScope.resolveIdentifierConflict(
851 self, scope, identifier, originalObject, newObject
854 if isinstance(newObject, IDLMethod):
855 if newObject.isStatic():
856 originalOperations.static = retval
857 else:
858 originalOperations.regular = retval
860 retval = originalOperations
862 # Might be a ctor, which isn't in self.members
863 if newObject in self.members:
864 self.members.remove(newObject)
865 return retval
867 def typeName(self):
868 if self.isInterface():
869 return "interface"
870 if self.isNamespace():
871 return "namespace"
872 assert self.isInterfaceMixin()
873 return "interface mixin"
875 def addExtendedAttributes(self, attrs):
876 for attr in attrs:
877 self.handleExtendedAttribute(attr)
878 attrlist = attr.listValue()
879 self._extendedAttrDict[attr.identifier()] = (
880 attrlist if len(attrlist) else True
883 def handleExtendedAttribute(self, attr):
884 identifier = attr.identifier()
885 if identifier == "Exposed":
886 convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
887 elif identifier == "SecureContext":
888 if not attr.noArguments():
889 raise WebIDLError(
890 "[SecureContext] must take no arguments", [attr.location]
892 # This gets propagated to all our members.
893 for member in self.members:
894 if member.getExtendedAttribute("SecureContext"):
895 typeName = self.typeName()
896 raise WebIDLError(
897 "[SecureContext] specified on both an %s member and on "
898 "%s itself" % (typeName, typeName),
899 [member.location, attr.location],
901 member.addExtendedAttributes([attr])
902 else:
903 raise WebIDLError(
904 "Unknown extended attribute %s on %s" % (identifier, self.typeName()),
905 [attr.location],
908 def getExtendedAttribute(self, name):
909 return self._extendedAttrDict.get(name, None)
911 def setNonPartial(self, location, members):
912 if self._isKnownNonPartial:
913 raise WebIDLError(
914 "Two non-partial definitions for the same %s" % self.typeName(),
915 [location, self.location],
917 self._isKnownNonPartial = True
918 # Now make it look like we were parsed at this new location, since
919 # that's the place where the interface is "really" defined
920 self.location = location
921 # Put the new members at the beginning
922 self.members = members + self.members
924 def addPartial(self, partial):
925 assert self.identifier.name == partial.identifier.name
926 self._partials.append(partial)
928 def getPartials(self):
929 # Don't let people mutate our guts.
930 return list(self._partials)
932 def finishMembers(self, scope):
933 # Assuming we've merged in our partials, set the _exposureGlobalNames on
934 # any members that don't have it set yet. Note that any partial
935 # interfaces that had [Exposed] set have already set up
936 # _exposureGlobalNames on all the members coming from them, so this is
937 # just implementing the "members default to interface or interface mixin
938 # that defined them" and "partial interfaces or interface mixins default
939 # to interface or interface mixin they're a partial for" rules from the
940 # spec.
941 for m in self.members:
942 # If m, or the partial m came from, had [Exposed]
943 # specified, it already has a nonempty exposure global names set.
944 if len(m._exposureGlobalNames) == 0:
945 m._exposureGlobalNames.update(self._exposureGlobalNames)
946 if m.isAttr() and m.stringifier:
947 m.expand(self.members)
949 # resolve() will modify self.members, so we need to iterate
950 # over a copy of the member list here.
951 for member in list(self.members):
952 member.resolve(self)
954 for member in self.members:
955 member.finish(scope)
957 # Now that we've finished our members, which has updated their exposure
958 # sets, make sure they aren't exposed in places where we are not.
959 for member in self.members:
960 if not member.exposureSet.issubset(self.exposureSet):
961 raise WebIDLError(
962 "Interface or interface mixin member has "
963 "larger exposure set than its container",
964 [member.location, self.location],
967 def isExternal(self):
968 return False
971 class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace):
972 __slots__ = ("actualExposureGlobalNames",)
974 def __init__(self, location, parentScope, name, members, isKnownNonPartial):
975 self.actualExposureGlobalNames = set()
977 assert isKnownNonPartial or not members
978 IDLInterfaceOrInterfaceMixinOrNamespace.__init__(
979 self, location, parentScope, name
982 if isKnownNonPartial:
983 self.setNonPartial(location, members)
985 def __str__(self):
986 return "Interface mixin '%s'" % self.identifier.name
988 def isInterfaceMixin(self):
989 return True
991 def finish(self, scope):
992 if self._finished:
993 return
994 self._finished = True
996 # Expose to the globals of interfaces that includes this mixin if this
997 # mixin has no explicit [Exposed] so that its members can be exposed
998 # based on the base interface exposure set.
1000 # Make sure this is done before IDLExposureMixins.finish call, since
1001 # that converts our set of exposure global names to an actual exposure
1002 # set.
1003 hasImplicitExposure = len(self._exposureGlobalNames) == 0
1004 if hasImplicitExposure:
1005 self._exposureGlobalNames.update(self.actualExposureGlobalNames)
1007 IDLInterfaceOrInterfaceMixinOrNamespace.finish(self, scope)
1009 self.finishMembers(scope)
1011 def validate(self):
1012 for member in self.members:
1013 if member.isAttr():
1014 if member.inherit:
1015 raise WebIDLError(
1016 "Interface mixin member cannot include "
1017 "an inherited attribute",
1018 [member.location, self.location],
1020 if member.isStatic():
1021 raise WebIDLError(
1022 "Interface mixin member cannot include a static member",
1023 [member.location, self.location],
1026 if member.isMethod():
1027 if member.isStatic():
1028 raise WebIDLError(
1029 "Interface mixin member cannot include a static operation",
1030 [member.location, self.location],
1032 if (
1033 member.isGetter()
1034 or member.isSetter()
1035 or member.isDeleter()
1036 or member.isLegacycaller()
1038 raise WebIDLError(
1039 "Interface mixin member cannot include a special operation",
1040 [member.location, self.location],
1043 def _getDependentObjects(self):
1044 return set(self.members)
1047 class ReflectedHTMLAttributesReturningFrozenArray(object):
1048 __slots__ = (
1049 "slotIndex",
1050 "totalMembersInSlots",
1053 def __init__(self, slotIndex):
1054 self.slotIndex = slotIndex
1055 self.totalMembersInSlots = 0
1058 class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
1059 __slots__ = (
1060 "parent",
1061 "_callback",
1062 "maplikeOrSetlikeOrIterable",
1063 "legacyFactoryFunctions",
1064 "legacyWindowAliases",
1065 "includedMixins",
1066 "interfacesBasedOnSelf",
1067 "_hasChildInterfaces",
1068 "_isOnGlobalProtoChain",
1069 "totalMembersInSlots",
1070 "_ownMembersInSlots",
1071 "reflectedHTMLAttributesReturningFrozenArray",
1072 "iterableInterface",
1073 "asyncIterableInterface",
1074 "hasCrossOriginMembers",
1075 "hasDescendantWithCrossOriginMembers",
1078 def __init__(self, location, parentScope, name, parent, members, isKnownNonPartial):
1079 assert isKnownNonPartial or not parent
1080 assert isKnownNonPartial or not members
1082 self.parent = None
1083 self._callback = False
1084 self.maplikeOrSetlikeOrIterable = None
1085 # legacyFactoryFunctions needs deterministic ordering because bindings code
1086 # outputs the constructs in the order that legacyFactoryFunctions enumerates
1087 # them.
1088 self.legacyFactoryFunctions = []
1089 self.legacyWindowAliases = []
1090 self.includedMixins = set()
1091 # self.interfacesBasedOnSelf is the set of interfaces that inherit from
1092 # self, including self itself.
1093 # Used for distinguishability checking.
1094 self.interfacesBasedOnSelf = {self}
1095 self._hasChildInterfaces = False
1096 self._isOnGlobalProtoChain = False
1098 # Tracking of the number of reserved slots we need for our members and
1099 # those of ancestor interfaces. Note that reflected HTML attributes that
1100 # have a FrozenArray<Element> return value also need to be stored in
1101 # slots. Because we don't want to use a lot of memory to store them when
1102 # they are not in use we use two levels of storage, the slot points to
1103 # an array of slots, so these have two indices. These attributes share
1104 # 1 slot in totalMembersInSlots, and count for 1 slot each in
1105 # reflectedHTMLAttributesReturningFrozenArray.totalMembersInSlots.
1106 self.totalMembersInSlots = 0
1107 # Tracking of the number of own own members we have in slots
1108 self._ownMembersInSlots = 0
1109 # Tracking the slot in the binding object for reflected HTML attributes
1110 # that return a FrozenArray, and the slot in the array stored in that
1111 # slot in the binding object.
1112 self.reflectedHTMLAttributesReturningFrozenArray = None
1113 # If this is an iterator interface, we need to know what iterable
1114 # interface we're iterating for in order to get its nativeType.
1115 self.iterableInterface = None
1116 self.asyncIterableInterface = None
1117 # True if we have cross-origin members.
1118 self.hasCrossOriginMembers = False
1119 # True if some descendant (including ourselves) has cross-origin members
1120 self.hasDescendantWithCrossOriginMembers = False
1122 IDLInterfaceOrInterfaceMixinOrNamespace.__init__(
1123 self, location, parentScope, name
1126 if isKnownNonPartial:
1127 self.setNonPartial(location, parent, members)
1129 def ctor(self):
1130 identifier = IDLUnresolvedIdentifier(
1131 self.location, "constructor", allowForbidden=True
1133 try:
1134 return self._lookupIdentifier(identifier).static
1135 except Exception:
1136 return None
1138 def isIterable(self):
1139 return (
1140 self.maplikeOrSetlikeOrIterable
1141 and self.maplikeOrSetlikeOrIterable.isIterable()
1144 def isAsyncIterable(self):
1145 return (
1146 self.maplikeOrSetlikeOrIterable
1147 and self.maplikeOrSetlikeOrIterable.isAsyncIterable()
1150 def isIteratorInterface(self):
1151 return self.iterableInterface is not None
1153 def isAsyncIteratorInterface(self):
1154 return self.asyncIterableInterface is not None
1156 def getClassName(self):
1157 return self.identifier.name
1159 def finish(self, scope):
1160 if self._finished:
1161 return
1163 self._finished = True
1165 IDLInterfaceOrInterfaceMixinOrNamespace.finish(self, scope)
1167 if len(self.legacyWindowAliases) > 0:
1168 if not self.hasInterfaceObject():
1169 raise WebIDLError(
1170 "Interface %s unexpectedly has [LegacyWindowAlias] "
1171 "and [LegacyNoInterfaceObject] together" % self.identifier.name,
1172 [self.location],
1174 if not self.isExposedInWindow():
1175 raise WebIDLError(
1176 "Interface %s has [LegacyWindowAlias] "
1177 "but not exposed in Window" % self.identifier.name,
1178 [self.location],
1181 # Generate maplike/setlike interface members. Since generated members
1182 # need to be treated like regular interface members, do this before
1183 # things like exposure setting.
1184 for member in self.members:
1185 if member.isMaplikeOrSetlikeOrIterable():
1186 if self.isJSImplemented():
1187 raise WebIDLError(
1188 "%s declaration used on "
1189 "interface that is implemented in JS"
1190 % (member.maplikeOrSetlikeOrIterableType),
1191 [member.location],
1193 if member.valueType.isObservableArray() or (
1194 member.hasKeyType() and member.keyType.isObservableArray()
1196 raise WebIDLError(
1197 "%s declaration uses ObservableArray as value or key type"
1198 % (member.maplikeOrSetlikeOrIterableType),
1199 [member.location],
1201 # Check that we only have one interface declaration (currently
1202 # there can only be one maplike/setlike declaration per
1203 # interface)
1204 if self.maplikeOrSetlikeOrIterable:
1205 raise WebIDLError(
1206 "%s declaration used on "
1207 "interface that already has %s "
1208 "declaration"
1210 member.maplikeOrSetlikeOrIterableType,
1211 self.maplikeOrSetlikeOrIterable.maplikeOrSetlikeOrIterableType,
1213 [self.maplikeOrSetlikeOrIterable.location, member.location],
1215 self.maplikeOrSetlikeOrIterable = member
1216 # If we've got a maplike or setlike declaration, we'll be building all of
1217 # our required methods in Codegen. Generate members now.
1218 self.maplikeOrSetlikeOrIterable.expand(self.members)
1220 assert not self.parent or isinstance(self.parent, IDLIdentifierPlaceholder)
1221 parent = self.parent.finish(scope) if self.parent else None
1222 if parent and isinstance(parent, IDLExternalInterface):
1223 raise WebIDLError(
1224 "%s inherits from %s which does not have "
1225 "a definition" % (self.identifier.name, self.parent.identifier.name),
1226 [self.location],
1228 if parent and not isinstance(parent, IDLInterface):
1229 raise WebIDLError(
1230 "%s inherits from %s which is not an interface "
1231 % (self.identifier.name, self.parent.identifier.name),
1232 [self.location, parent.location],
1235 self.parent = parent
1237 assert iter(self.members)
1239 if self.isNamespace():
1240 assert not self.parent
1241 for m in self.members:
1242 if m.isAttr() or m.isMethod():
1243 if m.isStatic():
1244 raise WebIDLError(
1245 "Don't mark things explicitly static in namespaces",
1246 [self.location, m.location],
1248 # Just mark all our methods/attributes as static. The other
1249 # option is to duplicate the relevant InterfaceMembers
1250 # production bits but modified to produce static stuff to
1251 # start with, but that sounds annoying.
1252 m.forceStatic()
1254 if self.parent:
1255 self.parent.finish(scope)
1256 self.parent._hasChildInterfaces = True
1258 self.totalMembersInSlots = self.parent.totalMembersInSlots
1260 # Interfaces with [Global] must not have anything inherit from them
1261 if self.parent.getExtendedAttribute("Global"):
1262 # Note: This is not a self.parent.isOnGlobalProtoChain() check
1263 # because ancestors of a [Global] interface can have other
1264 # descendants.
1265 raise WebIDLError(
1266 "[Global] interface has another interface inheriting from it",
1267 [self.location, self.parent.location],
1270 # Make sure that we're not exposed in places where our parent is not
1271 if not self.exposureSet.issubset(self.parent.exposureSet):
1272 raise WebIDLError(
1273 "Interface %s is exposed in globals where its "
1274 "parent interface %s is not exposed."
1275 % (self.identifier.name, self.parent.identifier.name),
1276 [self.location, self.parent.location],
1279 # Callbacks must not inherit from non-callbacks.
1280 # XXXbz Can non-callbacks inherit from callbacks? Spec issue pending.
1281 if self.isCallback():
1282 if not self.parent.isCallback():
1283 raise WebIDLError(
1284 "Callback interface %s inheriting from "
1285 "non-callback interface %s"
1286 % (self.identifier.name, self.parent.identifier.name),
1287 [self.location, self.parent.location],
1289 elif self.parent.isCallback():
1290 raise WebIDLError(
1291 "Non-callback interface %s inheriting from "
1292 "callback interface %s"
1293 % (self.identifier.name, self.parent.identifier.name),
1294 [self.location, self.parent.location],
1297 # Interfaces which have interface objects can't inherit
1298 # from [LegacyNoInterfaceObject] interfaces.
1299 if self.parent.getExtendedAttribute(
1300 "LegacyNoInterfaceObject"
1301 ) and not self.getExtendedAttribute("LegacyNoInterfaceObject"):
1302 raise WebIDLError(
1303 "Interface %s does not have "
1304 "[LegacyNoInterfaceObject] but inherits from "
1305 "interface %s which does"
1306 % (self.identifier.name, self.parent.identifier.name),
1307 [self.location, self.parent.location],
1310 # Interfaces that are not [SecureContext] can't inherit
1311 # from [SecureContext] interfaces.
1312 if self.parent.getExtendedAttribute(
1313 "SecureContext"
1314 ) and not self.getExtendedAttribute("SecureContext"):
1315 raise WebIDLError(
1316 "Interface %s does not have "
1317 "[SecureContext] but inherits from "
1318 "interface %s which does"
1319 % (self.identifier.name, self.parent.identifier.name),
1320 [self.location, self.parent.location],
1323 for mixin in self.includedMixins:
1324 mixin.finish(scope)
1326 cycleInGraph = self.findInterfaceLoopPoint(self)
1327 if cycleInGraph:
1328 raise WebIDLError(
1329 "Interface %s has itself as ancestor" % self.identifier.name,
1330 [self.location, cycleInGraph.location],
1333 self.finishMembers(scope)
1335 ctor = self.ctor()
1336 if ctor is not None:
1337 if not self.hasInterfaceObject():
1338 raise WebIDLError(
1339 "Can't have both a constructor and [LegacyNoInterfaceObject]",
1340 [self.location, ctor.location],
1343 if self.globalNames:
1344 raise WebIDLError(
1345 "Can't have both a constructor and [Global]",
1346 [self.location, ctor.location],
1349 assert ctor._exposureGlobalNames == self._exposureGlobalNames
1350 ctor._exposureGlobalNames.update(self._exposureGlobalNames)
1351 # Remove the constructor operation from our member list so
1352 # it doesn't get in the way later.
1353 self.members.remove(ctor)
1355 for ctor in self.legacyFactoryFunctions:
1356 if self.globalNames:
1357 raise WebIDLError(
1358 "Can't have both a legacy factory function and [Global]",
1359 [self.location, ctor.location],
1361 assert len(ctor._exposureGlobalNames) == 0
1362 ctor._exposureGlobalNames.update(self._exposureGlobalNames)
1363 ctor.finish(scope)
1365 # Make a copy of our member list, so things that implement us
1366 # can get those without all the stuff we implement ourselves
1367 # admixed.
1368 self.originalMembers = list(self.members)
1370 for mixin in sorted(self.includedMixins, key=lambda x: x.identifier.name):
1371 for mixinMember in mixin.members:
1372 for member in self.members:
1373 if mixinMember.identifier.name == member.identifier.name and (
1374 not mixinMember.isMethod()
1375 or not member.isMethod()
1376 or mixinMember.isStatic() == member.isStatic()
1378 raise WebIDLError(
1379 "Multiple definitions of %s on %s coming from 'includes' statements"
1380 % (member.identifier.name, self),
1381 [mixinMember.location, member.location],
1383 self.members.extend(mixin.members)
1385 for ancestor in self.getInheritedInterfaces():
1386 ancestor.interfacesBasedOnSelf.add(self)
1387 if (
1388 ancestor.maplikeOrSetlikeOrIterable is not None
1389 and self.maplikeOrSetlikeOrIterable is not None
1391 raise WebIDLError(
1392 "Cannot have maplike/setlike on %s that "
1393 "inherits %s, which is already "
1394 "maplike/setlike"
1395 % (self.identifier.name, ancestor.identifier.name),
1397 self.maplikeOrSetlikeOrIterable.location,
1398 ancestor.maplikeOrSetlikeOrIterable.location,
1402 # Deal with interfaces marked [LegacyUnforgeable], now that we have our full
1403 # member list, except unforgeables pulled in from parents. We want to
1404 # do this before we set "originatingInterface" on our unforgeable
1405 # members.
1406 if self.getExtendedAttribute("LegacyUnforgeable"):
1407 # Check that the interface already has all the things the
1408 # spec would otherwise require us to synthesize and is
1409 # missing the ones we plan to synthesize.
1410 if not any(m.isMethod() and m.isStringifier() for m in self.members):
1411 raise WebIDLError(
1412 "LegacyUnforgeable interface %s does not have a "
1413 "stringifier" % self.identifier.name,
1414 [self.location],
1417 for m in self.members:
1418 if m.identifier.name == "toJSON":
1419 raise WebIDLError(
1420 "LegacyUnforgeable interface %s has a "
1421 "toJSON so we won't be able to add "
1422 "one ourselves" % self.identifier.name,
1423 [self.location, m.location],
1426 if m.identifier.name == "valueOf" and not m.isStatic():
1427 raise WebIDLError(
1428 "LegacyUnforgeable interface %s has a valueOf "
1429 "member so we won't be able to add one "
1430 "ourselves" % self.identifier.name,
1431 [self.location, m.location],
1434 for member in self.members:
1435 if (
1436 (member.isAttr() or member.isMethod())
1437 and member.isLegacyUnforgeable()
1438 and not hasattr(member, "originatingInterface")
1440 member.originatingInterface = self
1442 for member in self.members:
1443 if (
1444 member.isMethod() and member.getExtendedAttribute("CrossOriginCallable")
1445 ) or (
1446 member.isAttr()
1447 and (
1448 member.getExtendedAttribute("CrossOriginReadable")
1449 or member.getExtendedAttribute("CrossOriginWritable")
1452 self.hasCrossOriginMembers = True
1453 break
1455 if self.hasCrossOriginMembers:
1456 parent = self
1457 while parent:
1458 parent.hasDescendantWithCrossOriginMembers = True
1459 parent = parent.parent
1461 # Compute slot indices for our members before we pull in unforgeable
1462 # members from our parent. Also, maplike/setlike declarations get a
1463 # slot to hold their backing object.
1464 for member in self.members:
1465 if (
1466 member.isAttr()
1467 and (
1468 member.getExtendedAttribute("StoreInSlot")
1469 or member.getExtendedAttribute("Cached")
1470 or member.type.isObservableArray()
1471 or member.getExtendedAttribute(
1472 "ReflectedHTMLAttributeReturningFrozenArray"
1475 ) or member.isMaplikeOrSetlike():
1476 if self.isJSImplemented() and not member.isMaplikeOrSetlike():
1477 raise WebIDLError(
1478 "Interface %s is JS-implemented and we "
1479 "don't support [Cached] or [StoreInSlot] or ObservableArray "
1480 "on JS-implemented interfaces" % self.identifier.name,
1481 [self.location, member.location],
1483 if member.slotIndices is None:
1484 member.slotIndices = dict()
1485 if member.getExtendedAttribute(
1486 "ReflectedHTMLAttributeReturningFrozenArray"
1488 parent = self.parent
1489 while parent:
1490 if self.parent.reflectedHTMLAttributesReturningFrozenArray:
1491 raise WebIDLError(
1492 "Interface %s has at least one attribute marked "
1493 "as[ReflectedHTMLAttributeReturningFrozenArray],"
1494 "but one of its ancestors also has an attribute "
1495 "marked as "
1496 "[ReflectedHTMLAttributeReturningFrozenArray]"
1497 % self.identifier.name,
1498 [self.location, member.location, parent.location],
1500 parent = parent.parent
1502 if not self.reflectedHTMLAttributesReturningFrozenArray:
1503 self.reflectedHTMLAttributesReturningFrozenArray = (
1504 ReflectedHTMLAttributesReturningFrozenArray(
1505 self.totalMembersInSlots
1508 self.totalMembersInSlots += 1
1509 member.slotIndices[self.identifier.name] = (
1510 self.reflectedHTMLAttributesReturningFrozenArray.slotIndex,
1511 self.reflectedHTMLAttributesReturningFrozenArray.totalMembersInSlots,
1513 self.reflectedHTMLAttributesReturningFrozenArray.totalMembersInSlots += (
1516 else:
1517 member.slotIndices[self.identifier.name] = self.totalMembersInSlots
1518 self.totalMembersInSlots += 1
1519 if member.getExtendedAttribute("StoreInSlot"):
1520 self._ownMembersInSlots += 1
1522 if self.parent:
1523 # Make sure we don't shadow any of the [LegacyUnforgeable] attributes on our
1524 # ancestor interfaces. We don't have to worry about mixins here, because
1525 # those have already been imported into the relevant .members lists. And
1526 # we don't have to worry about anything other than our parent, because it
1527 # has already imported its ancestors' unforgeable attributes into its
1528 # member list.
1529 for unforgeableMember in (
1530 member
1531 for member in self.parent.members
1532 if (member.isAttr() or member.isMethod())
1533 and member.isLegacyUnforgeable()
1535 shadows = [
1537 for m in self.members
1538 if (m.isAttr() or m.isMethod())
1539 and not m.isStatic()
1540 and m.identifier.name == unforgeableMember.identifier.name
1542 if len(shadows) != 0:
1543 locs = [unforgeableMember.location] + [s.location for s in shadows]
1544 raise WebIDLError(
1545 "Interface %s shadows [LegacyUnforgeable] "
1546 "members of %s"
1547 % (self.identifier.name, ancestor.identifier.name),
1548 locs,
1550 # And now just stick it in our members, since we won't be
1551 # inheriting this down the proto chain. If we really cared we
1552 # could try to do something where we set up the unforgeable
1553 # attributes/methods of ancestor interfaces, with their
1554 # corresponding getters, on our interface, but that gets pretty
1555 # complicated and seems unnecessary.
1556 self.members.append(unforgeableMember)
1558 # At this point, we have all of our members. If the current interface
1559 # uses maplike/setlike, check for collisions anywhere in the current
1560 # interface or higher in the inheritance chain.
1561 if self.maplikeOrSetlikeOrIterable:
1562 testInterface = self
1563 isAncestor = False
1564 while testInterface:
1565 self.maplikeOrSetlikeOrIterable.checkCollisions(
1566 testInterface.members, isAncestor
1568 isAncestor = True
1569 testInterface = testInterface.parent
1571 # Ensure that there's at most one of each {named,indexed}
1572 # {getter,setter,deleter}, at most one stringifier,
1573 # and at most one legacycaller. Note that this last is not
1574 # quite per spec, but in practice no one overloads
1575 # legacycallers. Also note that in practice we disallow
1576 # indexed deleters, but it simplifies some other code to
1577 # treat deleter analogously to getter/setter by
1578 # prefixing it with "named".
1579 specialMembersSeen = {}
1580 for member in self.members:
1581 if not member.isMethod():
1582 continue
1584 if member.isGetter():
1585 memberType = "getters"
1586 elif member.isSetter():
1587 memberType = "setters"
1588 elif member.isDeleter():
1589 memberType = "deleters"
1590 elif member.isStringifier():
1591 memberType = "stringifiers"
1592 elif member.isLegacycaller():
1593 memberType = "legacycallers"
1594 else:
1595 continue
1597 if memberType != "stringifiers" and memberType != "legacycallers":
1598 if member.isNamed():
1599 memberType = "named " + memberType
1600 else:
1601 assert member.isIndexed()
1602 memberType = "indexed " + memberType
1604 if memberType in specialMembersSeen:
1605 raise WebIDLError(
1606 "Multiple " + memberType + " on %s" % (self),
1608 self.location,
1609 specialMembersSeen[memberType].location,
1610 member.location,
1614 specialMembersSeen[memberType] = member
1616 if self.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
1617 # Check that we have a named getter.
1618 if "named getters" not in specialMembersSeen:
1619 raise WebIDLError(
1620 "Interface with [LegacyUnenumerableNamedProperties] does "
1621 "not have a named getter",
1622 [self.location],
1624 ancestor = self.parent
1625 while ancestor:
1626 if ancestor.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
1627 raise WebIDLError(
1628 "Interface with [LegacyUnenumerableNamedProperties] "
1629 "inherits from another interface with "
1630 "[LegacyUnenumerableNamedProperties]",
1631 [self.location, ancestor.location],
1633 ancestor = ancestor.parent
1635 if self._isOnGlobalProtoChain:
1636 # Make sure we have no named setters or deleters
1637 for memberType in ["setter", "deleter"]:
1638 memberId = "named " + memberType + "s"
1639 if memberId in specialMembersSeen:
1640 raise WebIDLError(
1641 "Interface with [Global] has a named %s" % memberType,
1642 [self.location, specialMembersSeen[memberId].location],
1644 # Make sure we're not [LegacyOverrideBuiltIns]
1645 if self.getExtendedAttribute("LegacyOverrideBuiltIns"):
1646 raise WebIDLError(
1647 "Interface with [Global] also has [LegacyOverrideBuiltIns]",
1648 [self.location],
1650 # Mark all of our ancestors as being on the global's proto chain too
1651 parent = self.parent
1652 while parent:
1653 # Must not inherit from an interface with [LegacyOverrideBuiltIns]
1654 if parent.getExtendedAttribute("LegacyOverrideBuiltIns"):
1655 raise WebIDLError(
1656 "Interface with [Global] inherits from "
1657 "interface with [LegacyOverrideBuiltIns]",
1658 [self.location, parent.location],
1660 parent._isOnGlobalProtoChain = True
1661 parent = parent.parent
1663 def validate(self):
1664 def checkDuplicateNames(member, name, attributeName):
1665 for m in self.members:
1666 if m.identifier.name == name:
1667 raise WebIDLError(
1668 "[%s=%s] has same name as interface member"
1669 % (attributeName, name),
1670 [member.location, m.location],
1672 if m.isMethod() and m != member and name in m.aliases:
1673 raise WebIDLError(
1674 "conflicting [%s=%s] definitions" % (attributeName, name),
1675 [member.location, m.location],
1677 if m.isAttr() and m != member and name in m.bindingAliases:
1678 raise WebIDLError(
1679 "conflicting [%s=%s] definitions" % (attributeName, name),
1680 [member.location, m.location],
1683 # We also don't support inheriting from unforgeable interfaces.
1684 if self.getExtendedAttribute("LegacyUnforgeable") and self.hasChildInterfaces():
1685 locations = [self.location] + list(
1686 i.location for i in self.interfacesBasedOnSelf if i.parent == self
1688 raise WebIDLError(
1689 "%s is an unforgeable ancestor interface" % self.identifier.name,
1690 locations,
1693 ctor = self.ctor()
1694 if ctor is not None:
1695 ctor.validate()
1696 for namedCtor in self.legacyFactoryFunctions:
1697 namedCtor.validate()
1699 indexedGetter = None
1700 hasLengthAttribute = False
1701 for member in self.members:
1702 member.validate()
1704 if self.isCallback() and member.getExtendedAttribute("Replaceable"):
1705 raise WebIDLError(
1706 "[Replaceable] used on an attribute on "
1707 "interface %s which is a callback interface" % self.identifier.name,
1708 [self.location, member.location],
1711 # Check that PutForwards refers to another attribute and that no
1712 # cycles exist in forwarded assignments. Also check for a
1713 # integer-typed "length" attribute.
1714 if member.isAttr():
1715 if member.identifier.name == "length" and member.type.isInteger():
1716 hasLengthAttribute = True
1718 iface = self
1719 attr = member
1720 putForwards = attr.getExtendedAttribute("PutForwards")
1721 if putForwards and self.isCallback():
1722 raise WebIDLError(
1723 "[PutForwards] used on an attribute "
1724 "on interface %s which is a callback "
1725 "interface" % self.identifier.name,
1726 [self.location, member.location],
1729 while putForwards is not None:
1731 def findForwardedAttr(iface):
1732 while iface:
1733 for m in iface.members:
1734 if (
1735 not m.isAttr()
1736 or m.identifier.name != putForwards[0]
1738 continue
1739 if m == member:
1740 raise WebIDLError(
1741 "Cycle detected in forwarded "
1742 "assignments for attribute %s on "
1743 "%s" % (member.identifier.name, self),
1744 [member.location],
1746 return (iface, m)
1748 iface = iface.parent
1750 return (None, None)
1752 (forwardIface, forwardAttr) = findForwardedAttr(
1753 attr.type.unroll().inner
1755 if forwardAttr is None:
1756 raise WebIDLError(
1757 "Attribute %s on %s forwards to "
1758 "missing attribute %s"
1759 % (attr.identifier.name, iface, putForwards),
1760 [attr.location],
1763 iface = forwardIface
1764 attr = forwardAttr
1765 putForwards = attr.getExtendedAttribute("PutForwards")
1767 # Check that the name of an [Alias] doesn't conflict with an
1768 # interface member and whether we support indexed properties.
1769 if member.isMethod():
1770 if member.isGetter() and member.isIndexed():
1771 indexedGetter = member
1773 for alias in member.aliases:
1774 if self.isOnGlobalProtoChain():
1775 raise WebIDLError(
1776 "[Alias] must not be used on a "
1777 "[Global] interface operation",
1778 [member.location],
1780 if (
1781 member.getExtendedAttribute("Exposed")
1782 or member.getExtendedAttribute("ChromeOnly")
1783 or member.getExtendedAttribute("Pref")
1784 or member.getExtendedAttribute("Func")
1785 or member.getExtendedAttribute("Trial")
1786 or member.getExtendedAttribute("SecureContext")
1788 raise WebIDLError(
1789 "[Alias] must not be used on a "
1790 "conditionally exposed operation",
1791 [member.location],
1793 if member.isStatic():
1794 raise WebIDLError(
1795 "[Alias] must not be used on a static operation",
1796 [member.location],
1798 if member.isIdentifierLess():
1799 raise WebIDLError(
1800 "[Alias] must not be used on an "
1801 "identifierless operation",
1802 [member.location],
1804 if member.isLegacyUnforgeable():
1805 raise WebIDLError(
1806 "[Alias] must not be used on an "
1807 "[LegacyUnforgeable] operation",
1808 [member.location],
1811 checkDuplicateNames(member, alias, "Alias")
1813 # Check that the name of a [BindingAlias] doesn't conflict with an
1814 # interface member.
1815 if member.isAttr():
1816 for bindingAlias in member.bindingAliases:
1817 checkDuplicateNames(member, bindingAlias, "BindingAlias")
1819 # Conditional exposure makes no sense for interfaces with no
1820 # interface object.
1821 # And SecureContext makes sense for interfaces with no interface object,
1822 # since it is also propagated to interface members.
1823 if (
1824 self.isExposedConditionally(exclusions=["SecureContext"])
1825 and not self.hasInterfaceObject()
1827 raise WebIDLError(
1828 "Interface with no interface object is exposed conditionally",
1829 [self.location],
1832 # Value iterators are only allowed on interfaces with indexed getters,
1833 # and pair iterators are only allowed on interfaces without indexed
1834 # getters.
1835 if self.isIterable():
1836 iterableDecl = self.maplikeOrSetlikeOrIterable
1837 if iterableDecl.isValueIterator():
1838 if not indexedGetter:
1839 raise WebIDLError(
1840 "Interface with value iterator does not "
1841 "support indexed properties",
1842 [self.location, iterableDecl.location],
1845 if iterableDecl.valueType != indexedGetter.signatures()[0][0]:
1846 raise WebIDLError(
1847 "Iterable type does not match indexed getter type",
1848 [iterableDecl.location, indexedGetter.location],
1851 if not hasLengthAttribute:
1852 raise WebIDLError(
1853 "Interface with value iterator does not "
1854 'have an integer-typed "length" attribute',
1855 [self.location, iterableDecl.location],
1857 else:
1858 assert iterableDecl.isPairIterator()
1859 if indexedGetter:
1860 raise WebIDLError(
1861 "Interface with pair iterator supports indexed properties",
1862 [self.location, iterableDecl.location, indexedGetter.location],
1865 if indexedGetter and not hasLengthAttribute:
1866 raise WebIDLError(
1867 "Interface with an indexed getter does not have "
1868 'an integer-typed "length" attribute',
1869 [self.location, indexedGetter.location],
1872 def setCallback(self, value):
1873 self._callback = value
1875 def isCallback(self):
1876 return self._callback
1878 def isSingleOperationInterface(self):
1879 assert self.isCallback() or self.isJSImplemented()
1880 return (
1881 # JS-implemented things should never need the
1882 # this-handling weirdness of single-operation interfaces.
1883 not self.isJSImplemented()
1885 # Not inheriting from another interface
1886 not self.parent
1888 # No attributes of any kinds
1889 not any(m.isAttr() for m in self.members)
1891 # There is at least one regular operation, and all regular
1892 # operations have the same identifier
1893 len(
1894 set(
1895 m.identifier.name
1896 for m in self.members
1897 if m.isMethod() and not m.isStatic()
1900 == 1
1903 def inheritanceDepth(self):
1904 depth = 0
1905 parent = self.parent
1906 while parent:
1907 depth = depth + 1
1908 parent = parent.parent
1909 return depth
1911 def hasConstants(self):
1912 return any(m.isConst() for m in self.members)
1914 def hasInterfaceObject(self):
1915 if self.isCallback():
1916 return self.hasConstants()
1917 return not hasattr(self, "_noInterfaceObject") and not self.getUserData(
1918 "hasOrdinaryObjectPrototype", False
1921 def hasInterfacePrototypeObject(self):
1922 return (
1923 not self.isCallback()
1924 and not self.isNamespace()
1925 and self.getUserData("hasConcreteDescendant", False)
1926 and not self.getUserData("hasOrdinaryObjectPrototype", False)
1929 def addIncludedMixin(self, includedMixin):
1930 assert isinstance(includedMixin, IDLInterfaceMixin)
1931 self.includedMixins.add(includedMixin)
1933 def getInheritedInterfaces(self):
1935 Returns a list of the interfaces this interface inherits from
1936 (not including this interface itself). The list is in order
1937 from most derived to least derived.
1939 assert self._finished
1940 if not self.parent:
1941 return []
1942 parentInterfaces = self.parent.getInheritedInterfaces()
1943 parentInterfaces.insert(0, self.parent)
1944 return parentInterfaces
1946 def findInterfaceLoopPoint(self, otherInterface):
1948 Finds an interface amongst our ancestors that inherits from otherInterface.
1949 If there is no such interface, returns None.
1951 if self.parent:
1952 if self.parent == otherInterface:
1953 return self
1954 loopPoint = self.parent.findInterfaceLoopPoint(otherInterface)
1955 if loopPoint:
1956 return loopPoint
1957 return None
1959 def setNonPartial(self, location, parent, members):
1960 assert not parent or isinstance(parent, IDLIdentifierPlaceholder)
1961 IDLInterfaceOrInterfaceMixinOrNamespace.setNonPartial(self, location, members)
1962 assert not self.parent
1963 self.parent = parent
1965 def getJSImplementation(self):
1966 classId = self.getExtendedAttribute("JSImplementation")
1967 if not classId:
1968 return classId
1969 assert isinstance(classId, list)
1970 assert len(classId) == 1
1971 return classId[0]
1973 def isJSImplemented(self):
1974 return bool(self.getJSImplementation())
1976 def hasProbablyShortLivingWrapper(self):
1977 current = self
1978 while current:
1979 if current.getExtendedAttribute("ProbablyShortLivingWrapper"):
1980 return True
1981 current = current.parent
1982 return False
1984 def hasChildInterfaces(self):
1985 return self._hasChildInterfaces
1987 def isOnGlobalProtoChain(self):
1988 return self._isOnGlobalProtoChain
1990 def _getDependentObjects(self):
1991 deps = set(self.members)
1992 deps.update(self.includedMixins)
1993 if self.parent:
1994 deps.add(self.parent)
1995 return deps
1997 def hasMembersInSlots(self):
1998 return self._ownMembersInSlots != 0
2000 conditionExtendedAttributes = [
2001 "Pref",
2002 "ChromeOnly",
2003 "Func",
2004 "Trial",
2005 "SecureContext",
2008 def isExposedConditionally(self, exclusions=[]):
2009 return any(
2010 ((a not in exclusions) and self.getExtendedAttribute(a))
2011 for a in self.conditionExtendedAttributes
2015 class IDLInterface(IDLInterfaceOrNamespace):
2016 __slots__ = ("classNameOverride",)
2018 def __init__(
2019 self,
2020 location,
2021 parentScope,
2022 name,
2023 parent,
2024 members,
2025 isKnownNonPartial,
2026 classNameOverride=None,
2028 IDLInterfaceOrNamespace.__init__(
2029 self, location, parentScope, name, parent, members, isKnownNonPartial
2031 self.classNameOverride = classNameOverride
2033 def __str__(self):
2034 return "Interface '%s'" % self.identifier.name
2036 def isInterface(self):
2037 return True
2039 def getClassName(self):
2040 if self.classNameOverride:
2041 return self.classNameOverride
2042 return IDLInterfaceOrNamespace.getClassName(self)
2044 def handleExtendedAttribute(self, attr):
2045 identifier = attr.identifier()
2046 # Special cased attrs
2047 if identifier == "TreatNonCallableAsNull":
2048 raise WebIDLError(
2049 "TreatNonCallableAsNull cannot be specified on interfaces",
2050 [attr.location, self.location],
2052 if identifier == "LegacyTreatNonObjectAsNull":
2053 raise WebIDLError(
2054 "LegacyTreatNonObjectAsNull cannot be specified on interfaces",
2055 [attr.location, self.location],
2057 elif identifier == "LegacyNoInterfaceObject":
2058 if not attr.noArguments():
2059 raise WebIDLError(
2060 "[LegacyNoInterfaceObject] must take no arguments",
2061 [attr.location],
2064 self._noInterfaceObject = True
2065 elif identifier == "LegacyFactoryFunction":
2066 if not attr.hasValue():
2067 raise WebIDLError(
2069 "LegacyFactoryFunction must either take an "
2070 "identifier or take a named argument list"
2072 [attr.location],
2075 args = attr.args() if attr.hasArgs() else []
2077 method = IDLConstructor(attr.location, args, attr.value())
2078 method.reallyInit(self)
2080 # Legacy factory functions are always assumed to be able to
2081 # throw (since there's no way to indicate otherwise).
2082 method.addExtendedAttributes(
2083 [IDLExtendedAttribute(self.location, ("Throws",))]
2086 # We need to detect conflicts for LegacyFactoryFunctions across
2087 # interfaces. We first call resolve on the parentScope,
2088 # which will merge all LegacyFactoryFunctions with the same
2089 # identifier accross interfaces as overloads.
2090 method.resolve(self.parentScope)
2092 # Then we look up the identifier on the parentScope. If the
2093 # result is the same as the method we're adding then it
2094 # hasn't been added as an overload and it's the first time
2095 # we've encountered a LegacyFactoryFunction with that identifier.
2096 # If the result is not the same as the method we're adding
2097 # then it has been added as an overload and we need to check
2098 # whether the result is actually one of our existing
2099 # LegacyFactoryFunctions.
2100 newMethod = self.parentScope.lookupIdentifier(method.identifier)
2101 if newMethod == method:
2102 self.legacyFactoryFunctions.append(method)
2103 elif newMethod not in self.legacyFactoryFunctions:
2104 raise WebIDLError(
2105 "LegacyFactoryFunction conflicts with a "
2106 "LegacyFactoryFunction of a different interface",
2107 [method.location, newMethod.location],
2109 elif identifier == "ExceptionClass":
2110 if not attr.noArguments():
2111 raise WebIDLError(
2112 "[ExceptionClass] must take no arguments", [attr.location]
2114 if self.parent:
2115 raise WebIDLError(
2116 "[ExceptionClass] must not be specified on "
2117 "an interface with inherited interfaces",
2118 [attr.location, self.location],
2120 elif identifier == "Global":
2121 if attr.hasValue():
2122 self.globalNames = [attr.value()]
2123 elif attr.hasArgs():
2124 self.globalNames = attr.args()
2125 else:
2126 raise WebIDLError(
2127 "[Global] must either take an identifier or take an identifier list",
2128 [attr.location, self.location],
2130 self.parentScope.addIfaceGlobalNames(self.identifier.name, self.globalNames)
2131 self._isOnGlobalProtoChain = True
2132 elif identifier == "LegacyWindowAlias":
2133 if attr.hasValue():
2134 self.legacyWindowAliases = [attr.value()]
2135 elif attr.hasArgs():
2136 self.legacyWindowAliases = attr.args()
2137 else:
2138 raise WebIDLError(
2139 "[%s] must either take an identifier "
2140 "or take an identifier list" % identifier,
2141 [attr.location],
2143 for alias in self.legacyWindowAliases:
2144 unresolved = IDLUnresolvedIdentifier(attr.location, alias)
2145 IDLObjectWithIdentifier(attr.location, self.parentScope, unresolved)
2146 elif (
2147 identifier == "NeedResolve"
2148 or identifier == "LegacyOverrideBuiltIns"
2149 or identifier == "ChromeOnly"
2150 or identifier == "LegacyUnforgeable"
2151 or identifier == "LegacyEventInit"
2152 or identifier == "ProbablyShortLivingWrapper"
2153 or identifier == "LegacyUnenumerableNamedProperties"
2154 or identifier == "RunConstructorInCallerCompartment"
2155 or identifier == "WantsEventListenerHooks"
2156 or identifier == "Serializable"
2158 # Known extended attributes that do not take values
2159 if not attr.noArguments():
2160 raise WebIDLError(
2161 "[%s] must take no arguments" % identifier, [attr.location]
2163 elif (
2164 identifier == "Pref"
2165 or identifier == "JSImplementation"
2166 or identifier == "HeaderFile"
2167 or identifier == "Func"
2168 or identifier == "Trial"
2169 or identifier == "Deprecated"
2171 # Known extended attributes that take a string value
2172 if not attr.hasValue():
2173 raise WebIDLError(
2174 "[%s] must have a value" % identifier, [attr.location]
2176 elif identifier == "InstrumentedProps":
2177 # Known extended attributes that take a list
2178 if not attr.hasArgs():
2179 raise WebIDLError(
2180 "[%s] must have arguments" % identifier, [attr.location]
2182 else:
2183 IDLInterfaceOrNamespace.handleExtendedAttribute(self, attr)
2185 def validate(self):
2186 IDLInterfaceOrNamespace.validate(self)
2187 if self.parent and self.isSerializable() and not self.parent.isSerializable():
2188 raise WebIDLError(
2189 "Serializable interface inherits from non-serializable "
2190 "interface. Per spec, that means the object should not be "
2191 "serializable, so chances are someone made a mistake here "
2192 "somewhere.",
2193 [self.location, self.parent.location],
2196 def isSerializable(self):
2197 return self.getExtendedAttribute("Serializable")
2199 def setNonPartial(self, location, parent, members):
2200 # Before we do anything else, finish initializing any constructors that
2201 # might be in "members", so we don't have partially-initialized objects
2202 # hanging around. We couldn't do it before now because we needed to have
2203 # to have the IDLInterface on hand to properly set the return type.
2204 for member in members:
2205 if isinstance(member, IDLConstructor):
2206 member.reallyInit(self)
2208 IDLInterfaceOrNamespace.setNonPartial(self, location, parent, members)
2211 class IDLNamespace(IDLInterfaceOrNamespace):
2212 __slots__ = ()
2214 def __init__(self, location, parentScope, name, members, isKnownNonPartial):
2215 IDLInterfaceOrNamespace.__init__(
2216 self, location, parentScope, name, None, members, isKnownNonPartial
2219 def __str__(self):
2220 return "Namespace '%s'" % self.identifier.name
2222 def isNamespace(self):
2223 return True
2225 def handleExtendedAttribute(self, attr):
2226 # The set of things namespaces support is small enough it's simpler
2227 # to factor out into a separate method than it is to sprinkle
2228 # isNamespace() checks all through
2229 # IDLInterfaceOrNamespace.handleExtendedAttribute.
2230 identifier = attr.identifier()
2231 if identifier == "ClassString":
2232 # Takes a string value to override the default "Object" if
2233 # desired.
2234 if not attr.hasValue():
2235 raise WebIDLError(
2236 "[%s] must have a value" % identifier, [attr.location]
2238 elif identifier == "ProtoObjectHack" or identifier == "ChromeOnly":
2239 if not attr.noArguments():
2240 raise WebIDLError(
2241 "[%s] must not have arguments" % identifier, [attr.location]
2243 elif (
2244 identifier == "Pref"
2245 or identifier == "HeaderFile"
2246 or identifier == "Func"
2247 or identifier == "Trial"
2249 # Known extended attributes that take a string value
2250 if not attr.hasValue():
2251 raise WebIDLError(
2252 "[%s] must have a value" % identifier, [attr.location]
2254 else:
2255 IDLInterfaceOrNamespace.handleExtendedAttribute(self, attr)
2257 def isSerializable(self):
2258 return False
2261 class IDLDictionary(IDLObjectWithScope):
2262 __slots__ = (
2263 "parent",
2264 "_finished",
2265 "members",
2266 "_partialDictionaries",
2267 "_extendedAttrDict",
2268 "needsConversionToJS",
2269 "needsConversionFromJS",
2270 "needsEqualityOperator",
2273 def __init__(self, location, parentScope, name, parent, members):
2274 assert isinstance(parentScope, IDLScope)
2275 assert isinstance(name, IDLUnresolvedIdentifier)
2276 assert not parent or isinstance(parent, IDLIdentifierPlaceholder)
2278 self.parent = parent
2279 self._finished = False
2280 self.members = list(members)
2281 self._partialDictionaries = []
2282 self._extendedAttrDict = {}
2283 self.needsConversionToJS = False
2284 self.needsConversionFromJS = False
2285 self.needsEqualityOperator = None
2287 IDLObjectWithScope.__init__(self, location, parentScope, name)
2289 def __str__(self):
2290 return "Dictionary '%s'" % self.identifier.name
2292 def isDictionary(self):
2293 return True
2295 def canBeEmpty(self):
2297 Returns true if this dictionary can be empty (that is, it has no
2298 required members and neither do any of its ancestors).
2300 return all(member.optional for member in self.members) and (
2301 not self.parent or self.parent.canBeEmpty()
2304 def finish(self, scope):
2305 if self._finished:
2306 return
2308 self._finished = True
2310 if self.parent:
2311 assert isinstance(self.parent, IDLIdentifierPlaceholder)
2312 oldParent = self.parent
2313 self.parent = self.parent.finish(scope)
2314 if not isinstance(self.parent, IDLDictionary):
2315 raise WebIDLError(
2316 "Dictionary %s has parent that is not a dictionary"
2317 % self.identifier.name,
2318 [oldParent.location, self.parent.location],
2321 # Make sure the parent resolves all its members before we start
2322 # looking at them.
2323 self.parent.finish(scope)
2325 # Now go ahead and merge in our partial dictionaries.
2326 for partial in self._partialDictionaries:
2327 partial.finish(scope)
2328 self.members.extend(partial.members)
2330 for member in self.members:
2331 member.resolve(self)
2332 if not member.isComplete():
2333 member.complete(scope)
2334 assert member.type.isComplete()
2336 # Members of a dictionary are sorted in lexicographic order,
2337 # unless the dictionary opts out.
2338 if not self.getExtendedAttribute("Unsorted"):
2339 self.members.sort(key=lambda x: x.identifier.name)
2341 inheritedMembers = []
2342 ancestor = self.parent
2343 while ancestor:
2344 if ancestor == self:
2345 raise WebIDLError(
2346 "Dictionary %s has itself as an ancestor" % self.identifier.name,
2347 [self.identifier.location],
2349 inheritedMembers.extend(ancestor.members)
2350 if (
2351 self.getExtendedAttribute("GenerateEqualityOperator")
2352 and ancestor.needsEqualityOperator is None
2354 # Store the dictionary that has the [GenerateEqualityOperator]
2355 # extended attribute, so we can use it when generating error
2356 # messages.
2357 ancestor.needsEqualityOperator = self
2358 ancestor = ancestor.parent
2360 # Catch name duplication
2361 for inheritedMember in inheritedMembers:
2362 for member in self.members:
2363 if member.identifier.name == inheritedMember.identifier.name:
2364 raise WebIDLError(
2365 "Dictionary %s has two members with name %s"
2366 % (self.identifier.name, member.identifier.name),
2367 [member.location, inheritedMember.location],
2370 def validate(self):
2371 def typeContainsDictionary(memberType, dictionary):
2373 Returns a tuple whose:
2375 - First element is a Boolean value indicating whether
2376 memberType contains dictionary.
2378 - Second element is:
2379 A list of locations that leads from the type that was passed in
2380 the memberType argument, to the dictionary being validated,
2381 if the boolean value in the first element is True.
2383 None, if the boolean value in the first element is False.
2386 if (
2387 memberType.nullable()
2388 or memberType.isSequence()
2389 or memberType.isRecord()
2391 return typeContainsDictionary(memberType.inner, dictionary)
2393 if memberType.isDictionary():
2394 if memberType.inner == dictionary:
2395 return (True, [memberType.location])
2397 (contains, locations) = dictionaryContainsDictionary(
2398 memberType.inner, dictionary
2400 if contains:
2401 return (True, [memberType.location] + locations)
2403 if memberType.isUnion():
2404 for member in memberType.flatMemberTypes:
2405 (contains, locations) = typeContainsDictionary(member, dictionary)
2406 if contains:
2407 return (True, locations)
2409 return (False, None)
2411 def dictionaryContainsDictionary(dictMember, dictionary):
2412 for member in dictMember.members:
2413 (contains, locations) = typeContainsDictionary(member.type, dictionary)
2414 if contains:
2415 return (True, [member.location] + locations)
2417 if dictMember.parent:
2418 if dictMember.parent == dictionary:
2419 return (True, [dictMember.location])
2420 else:
2421 (contains, locations) = dictionaryContainsDictionary(
2422 dictMember.parent, dictionary
2424 if contains:
2425 return (True, [dictMember.location] + locations)
2427 return (False, None)
2429 for member in self.members:
2430 if member.type.isDictionary() and member.type.nullable():
2431 raise WebIDLError(
2432 "Dictionary %s has member with nullable "
2433 "dictionary type" % self.identifier.name,
2434 [member.location],
2436 (contains, locations) = typeContainsDictionary(member.type, self)
2437 if contains:
2438 raise WebIDLError(
2439 "Dictionary %s has member with itself as type."
2440 % self.identifier.name,
2441 [member.location] + locations,
2444 if member.type.isUndefined():
2445 raise WebIDLError(
2446 "Dictionary %s has member with undefined as its type."
2447 % self.identifier.name,
2448 [member.location],
2450 elif member.type.isUnion():
2451 for unionMember in member.type.unroll().flatMemberTypes:
2452 if unionMember.isUndefined():
2453 raise WebIDLError(
2454 "Dictionary %s has member with a union containing "
2455 "undefined as a type." % self.identifier.name,
2456 [unionMember.location],
2459 def getExtendedAttribute(self, name):
2460 return self._extendedAttrDict.get(name, None)
2462 def addExtendedAttributes(self, attrs):
2463 for attr in attrs:
2464 identifier = attr.identifier()
2466 if identifier == "GenerateInitFromJSON" or identifier == "GenerateInit":
2467 if not attr.noArguments():
2468 raise WebIDLError(
2469 "[%s] must not have arguments" % identifier, [attr.location]
2471 self.needsConversionFromJS = True
2472 elif (
2473 identifier == "GenerateConversionToJS" or identifier == "GenerateToJSON"
2475 if not attr.noArguments():
2476 raise WebIDLError(
2477 "[%s] must not have arguments" % identifier, [attr.location]
2479 # ToJSON methods require to-JS conversion, because we
2480 # implement ToJSON by converting to a JS object and
2481 # then using JSON.stringify.
2482 self.needsConversionToJS = True
2483 elif identifier == "GenerateEqualityOperator":
2484 if not attr.noArguments():
2485 raise WebIDLError(
2486 "[GenerateEqualityOperator] must take no arguments",
2487 [attr.location],
2489 self.needsEqualityOperator = self
2490 elif identifier == "Unsorted":
2491 if not attr.noArguments():
2492 raise WebIDLError(
2493 "[Unsorted] must take no arguments", [attr.location]
2495 else:
2496 raise WebIDLError(
2497 "[%s] extended attribute not allowed on "
2498 "dictionaries" % identifier,
2499 [attr.location],
2502 self._extendedAttrDict[identifier] = True
2504 def _getDependentObjects(self):
2505 deps = set(self.members)
2506 if self.parent:
2507 deps.add(self.parent)
2508 return deps
2510 def addPartialDictionary(self, partial):
2511 assert self.identifier.name == partial.identifier.name
2512 self._partialDictionaries.append(partial)
2515 class IDLEnum(IDLObjectWithIdentifier):
2516 __slots__ = ("_values",)
2518 def __init__(self, location, parentScope, name, values):
2519 assert isinstance(parentScope, IDLScope)
2520 assert isinstance(name, IDLUnresolvedIdentifier)
2522 if len(values) != len(set(values)):
2523 raise WebIDLError(
2524 "Enum %s has multiple identical strings" % name.name, [location]
2527 IDLObjectWithIdentifier.__init__(self, location, parentScope, name)
2528 self._values = values
2530 def values(self):
2531 return self._values
2533 def finish(self, scope):
2534 pass
2536 def validate(self):
2537 pass
2539 def isEnum(self):
2540 return True
2542 def addExtendedAttributes(self, attrs):
2543 if len(attrs) != 0:
2544 raise WebIDLError(
2545 "There are no extended attributes that are allowed on enums",
2546 [attrs[0].location, self.location],
2549 def _getDependentObjects(self):
2550 return set()
2553 class IDLType(IDLObject):
2554 Tags = enum(
2555 # The integer types
2556 "int8",
2557 "uint8",
2558 "int16",
2559 "uint16",
2560 "int32",
2561 "uint32",
2562 "int64",
2563 "uint64",
2564 # Additional primitive types
2565 "bool",
2566 "unrestricted_float",
2567 "float",
2568 "unrestricted_double",
2569 # "double" last primitive type to match IDLBuiltinType
2570 "double",
2571 # Other types
2572 "any",
2573 "undefined",
2574 "domstring",
2575 "bytestring",
2576 "usvstring",
2577 "utf8string",
2578 "jsstring",
2579 "object",
2580 # Funny stuff
2581 "interface",
2582 "dictionary",
2583 "enum",
2584 "callback",
2585 "union",
2586 "sequence",
2587 "record",
2588 "promise",
2589 "observablearray",
2592 __slots__ = (
2593 "name",
2594 "builtin",
2595 "legacyNullToEmptyString",
2596 "_clamp",
2597 "_enforceRange",
2598 "_allowShared",
2599 "_extendedAttrDict",
2602 def __init__(self, location, name):
2603 IDLObject.__init__(self, location)
2604 self.name = name
2605 self.builtin = False
2606 self.legacyNullToEmptyString = False
2607 self._clamp = False
2608 self._enforceRange = False
2609 self._allowShared = False
2610 self._extendedAttrDict = {}
2612 def __hash__(self):
2613 return (
2614 hash(self.builtin)
2615 + hash(self.name)
2616 + hash(self._clamp)
2617 + hash(self._enforceRange)
2618 + hash(self.legacyNullToEmptyString)
2619 + hash(self._allowShared)
2622 def __eq__(self, other):
2623 return (
2624 other
2625 and self.builtin == other.builtin
2626 and self.name == other.name
2627 and self._clamp == other.hasClamp()
2628 and self._enforceRange == other.hasEnforceRange()
2629 and self.legacyNullToEmptyString == other.legacyNullToEmptyString
2630 and self._allowShared == other.hasAllowShared()
2633 def __ne__(self, other):
2634 return not self == other
2636 def __str__(self):
2637 return str(self.name)
2639 def prettyName(self):
2641 A name that looks like what this type is named in the IDL spec. By default
2642 this is just our .name, but types that have more interesting spec
2643 representations should override this.
2645 return str(self.name)
2647 def isType(self):
2648 return True
2650 def nullable(self):
2651 return False
2653 def isPrimitive(self):
2654 return False
2656 def isBoolean(self):
2657 return False
2659 def isNumeric(self):
2660 return False
2662 def isString(self):
2663 return False
2665 def isByteString(self):
2666 return False
2668 def isDOMString(self):
2669 return False
2671 def isUSVString(self):
2672 return False
2674 def isUTF8String(self):
2675 return False
2677 def isJSString(self):
2678 return False
2680 def isUndefined(self):
2681 return False
2683 def isSequence(self):
2684 return False
2686 def isRecord(self):
2687 return False
2689 def isArrayBuffer(self):
2690 return False
2692 def isArrayBufferView(self):
2693 return False
2695 def isTypedArray(self):
2696 return False
2698 def isBufferSource(self):
2699 return self.isArrayBuffer() or self.isArrayBufferView() or self.isTypedArray()
2701 def isCallbackInterface(self):
2702 return False
2704 def isNonCallbackInterface(self):
2705 return False
2707 def isGeckoInterface(self):
2708 """Returns a boolean indicating whether this type is an 'interface'
2709 type that is implemented in Gecko. At the moment, this returns
2710 true for all interface types that are not types from the TypedArray
2711 spec."""
2712 return self.isInterface() and not self.isSpiderMonkeyInterface()
2714 def isSpiderMonkeyInterface(self):
2715 """Returns a boolean indicating whether this type is an 'interface'
2716 type that is implemented in SpiderMonkey."""
2717 return self.isInterface() and self.isBufferSource()
2719 def isAny(self):
2720 return self.tag() == IDLType.Tags.any
2722 def isObject(self):
2723 return self.tag() == IDLType.Tags.object
2725 def isPromise(self):
2726 return False
2728 def isComplete(self):
2729 return True
2731 def includesRestrictedFloat(self):
2732 return False
2734 def isFloat(self):
2735 return False
2737 def isUnrestricted(self):
2738 # Should only call this on float types
2739 assert self.isFloat()
2741 def isJSONType(self):
2742 return False
2744 def isObservableArray(self):
2745 return False
2747 def isDictionaryLike(self):
2748 return self.isDictionary() or self.isRecord() or self.isCallbackInterface()
2750 def hasClamp(self):
2751 return self._clamp
2753 def hasEnforceRange(self):
2754 return self._enforceRange
2756 def hasAllowShared(self):
2757 return self._allowShared
2759 def tag(self):
2760 assert False # Override me!
2762 def treatNonCallableAsNull(self):
2763 assert self.tag() == IDLType.Tags.callback
2764 return self.nullable() and self.inner.callback._treatNonCallableAsNull
2766 def treatNonObjectAsNull(self):
2767 assert self.tag() == IDLType.Tags.callback
2768 return self.nullable() and self.inner.callback._treatNonObjectAsNull
2770 def withExtendedAttributes(self, attrs):
2771 if len(attrs) > 0:
2772 raise WebIDLError(
2773 "Extended attributes on types only supported for builtins",
2774 [attrs[0].location, self.location],
2776 return self
2778 def getExtendedAttribute(self, name):
2779 return self._extendedAttrDict.get(name, None)
2781 def resolveType(self, parentScope):
2782 pass
2784 def unroll(self):
2785 return self
2787 def isDistinguishableFrom(self, other):
2788 raise TypeError(
2789 "Can't tell whether a generic type is or is not "
2790 "distinguishable from other things"
2793 def isExposedInAllOf(self, exposureSet):
2794 return True
2797 class IDLUnresolvedType(IDLType):
2799 Unresolved types are interface types
2802 __slots__ = ("extraTypeAttributes",)
2804 def __init__(self, location, name, attrs=[]):
2805 IDLType.__init__(self, location, name)
2806 self.extraTypeAttributes = attrs
2808 def isComplete(self):
2809 return False
2811 def complete(self, scope):
2812 obj = None
2813 try:
2814 obj = scope._lookupIdentifier(self.name)
2815 except Exception:
2816 raise WebIDLError("Unresolved type '%s'." % self.name, [self.location])
2818 assert obj
2819 assert not obj.isType()
2820 if obj.isTypedef():
2821 assert self.name.name == obj.identifier.name
2822 typedefType = IDLTypedefType(self.location, obj.innerType, obj.identifier)
2823 assert not typedefType.isComplete()
2824 return typedefType.complete(scope).withExtendedAttributes(
2825 self.extraTypeAttributes
2827 elif obj.isCallback() and not obj.isInterface():
2828 assert self.name.name == obj.identifier.name
2829 return IDLCallbackType(self.location, obj)
2831 return IDLWrapperType(self.location, obj)
2833 def withExtendedAttributes(self, attrs):
2834 return IDLUnresolvedType(self.location, self.name, attrs)
2836 def isDistinguishableFrom(self, other):
2837 raise TypeError(
2838 "Can't tell whether an unresolved type is or is not "
2839 "distinguishable from other things"
2843 class IDLParametrizedType(IDLType):
2844 __slots__ = "builtin", "inner"
2846 def __init__(self, location, name, innerType):
2847 IDLType.__init__(self, location, name)
2848 self.builtin = False
2849 self.inner = innerType
2851 def includesRestrictedFloat(self):
2852 return self.inner.includesRestrictedFloat()
2854 def resolveType(self, parentScope):
2855 assert isinstance(parentScope, IDLScope)
2856 self.inner.resolveType(parentScope)
2858 def isComplete(self):
2859 return self.inner.isComplete()
2861 def unroll(self):
2862 return self.inner.unroll()
2864 def _getDependentObjects(self):
2865 return self.inner._getDependentObjects()
2868 class IDLNullableType(IDLParametrizedType):
2869 __slots__ = ()
2871 def __init__(self, location, innerType):
2872 assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any]
2874 IDLParametrizedType.__init__(self, location, None, innerType)
2876 def __hash__(self):
2877 return hash(self.inner)
2879 def __eq__(self, other):
2880 return isinstance(other, IDLNullableType) and self.inner == other.inner
2882 def __str__(self):
2883 return self.inner.__str__() + "OrNull"
2885 def prettyName(self):
2886 return self.inner.prettyName() + "?"
2888 def nullable(self):
2889 return True
2891 def isCallback(self):
2892 return self.inner.isCallback()
2894 def isPrimitive(self):
2895 return self.inner.isPrimitive()
2897 def isBoolean(self):
2898 return self.inner.isBoolean()
2900 def isNumeric(self):
2901 return self.inner.isNumeric()
2903 def isString(self):
2904 return self.inner.isString()
2906 def isByteString(self):
2907 return self.inner.isByteString()
2909 def isDOMString(self):
2910 return self.inner.isDOMString()
2912 def isUSVString(self):
2913 return self.inner.isUSVString()
2915 def isUTF8String(self):
2916 return self.inner.isUTF8String()
2918 def isJSString(self):
2919 return self.inner.isJSString()
2921 def isFloat(self):
2922 return self.inner.isFloat()
2924 def isUnrestricted(self):
2925 return self.inner.isUnrestricted()
2927 def isInteger(self):
2928 return self.inner.isInteger()
2930 def isUndefined(self):
2931 return self.inner.isUndefined()
2933 def isSequence(self):
2934 return self.inner.isSequence()
2936 def isRecord(self):
2937 return self.inner.isRecord()
2939 def isArrayBuffer(self):
2940 return self.inner.isArrayBuffer()
2942 def isArrayBufferView(self):
2943 return self.inner.isArrayBufferView()
2945 def isTypedArray(self):
2946 return self.inner.isTypedArray()
2948 def isDictionary(self):
2949 return self.inner.isDictionary()
2951 def isInterface(self):
2952 return self.inner.isInterface()
2954 def isPromise(self):
2955 # There is no such thing as a nullable Promise.
2956 assert not self.inner.isPromise()
2957 return False
2959 def isCallbackInterface(self):
2960 return self.inner.isCallbackInterface()
2962 def isNonCallbackInterface(self):
2963 return self.inner.isNonCallbackInterface()
2965 def isEnum(self):
2966 return self.inner.isEnum()
2968 def isUnion(self):
2969 return self.inner.isUnion()
2971 def isJSONType(self):
2972 return self.inner.isJSONType()
2974 def isObservableArray(self):
2975 return self.inner.isObservableArray()
2977 def hasClamp(self):
2978 return self.inner.hasClamp()
2980 def hasEnforceRange(self):
2981 return self.inner.hasEnforceRange()
2983 def hasAllowShared(self):
2984 return self.inner.hasAllowShared()
2986 def isComplete(self):
2987 return self.name is not None
2989 def tag(self):
2990 return self.inner.tag()
2992 def complete(self, scope):
2993 if not self.inner.isComplete():
2994 self.inner = self.inner.complete(scope)
2995 assert self.inner.isComplete()
2997 if self.inner.nullable():
2998 raise WebIDLError(
2999 "The inner type of a nullable type must not be a nullable type",
3000 [self.location, self.inner.location],
3002 if self.inner.isUnion():
3003 if self.inner.hasNullableType:
3004 raise WebIDLError(
3005 "The inner type of a nullable type must not "
3006 "be a union type that itself has a nullable "
3007 "type as a member type",
3008 [self.location],
3010 if self.inner.isDOMString():
3011 if self.inner.legacyNullToEmptyString:
3012 raise WebIDLError(
3013 "[LegacyNullToEmptyString] not allowed on a nullable DOMString",
3014 [self.location, self.inner.location],
3016 if self.inner.isObservableArray():
3017 raise WebIDLError(
3018 "The inner type of a nullable type must not be an ObservableArray type",
3019 [self.location, self.inner.location],
3022 self.name = self.inner.name + "OrNull"
3023 return self
3025 def isDistinguishableFrom(self, other):
3026 if (
3027 other.nullable()
3028 or other.isDictionary()
3029 or (
3030 other.isUnion() and (other.hasNullableType or other.hasDictionaryType())
3033 # Can't tell which type null should become
3034 return False
3035 return self.inner.isDistinguishableFrom(other)
3037 def withExtendedAttributes(self, attrs):
3038 # See https://github.com/heycam/webidl/issues/827#issuecomment-565131350
3039 # Allowing extended attributes to apply to a nullable type is an intermediate solution.
3040 # A potential longer term solution is to introduce a null type and get rid of nullables.
3041 # For example, we could do `([Clamp] long or null) foo` in the future.
3042 return IDLNullableType(self.location, self.inner.withExtendedAttributes(attrs))
3045 class IDLSequenceType(IDLParametrizedType):
3046 __slots__ = ("name",)
3048 def __init__(self, location, parameterType):
3049 assert not parameterType.isUndefined()
3051 IDLParametrizedType.__init__(self, location, parameterType.name, parameterType)
3052 # Need to set self.name up front if our inner type is already complete,
3053 # since in that case our .complete() won't be called.
3054 if self.inner.isComplete():
3055 self.name = self.inner.name + "Sequence"
3057 def __hash__(self):
3058 return hash(self.inner)
3060 def __eq__(self, other):
3061 return isinstance(other, IDLSequenceType) and self.inner == other.inner
3063 def __str__(self):
3064 return self.inner.__str__() + "Sequence"
3066 def prettyName(self):
3067 return "sequence<%s>" % self.inner.prettyName()
3069 def isSequence(self):
3070 return True
3072 def isJSONType(self):
3073 return self.inner.isJSONType()
3075 def tag(self):
3076 return IDLType.Tags.sequence
3078 def complete(self, scope):
3079 if self.inner.isObservableArray():
3080 raise WebIDLError(
3081 "The inner type of a sequence type must not be an ObservableArray type",
3082 [self.location, self.inner.location],
3085 self.inner = self.inner.complete(scope)
3086 self.name = self.inner.name + "Sequence"
3087 return self
3089 def isDistinguishableFrom(self, other):
3090 if other.isPromise():
3091 return False
3092 if other.isUnion():
3093 # Just forward to the union; it'll deal
3094 return other.isDistinguishableFrom(self)
3095 return (
3096 other.isUndefined()
3097 or other.isPrimitive()
3098 or other.isString()
3099 or other.isEnum()
3100 or other.isInterface()
3101 or other.isDictionary()
3102 or other.isCallback()
3103 or other.isRecord()
3107 class IDLRecordType(IDLParametrizedType):
3108 __slots__ = "keyType", "name"
3110 def __init__(self, location, keyType, valueType):
3111 assert keyType.isString()
3112 assert keyType.isComplete()
3114 if valueType.isUndefined():
3115 raise WebIDLError(
3116 "We don't support undefined as a Record's values' type",
3117 [location, valueType.location],
3120 IDLParametrizedType.__init__(self, location, valueType.name, valueType)
3121 self.keyType = keyType
3123 # Need to set self.name up front if our inner type is already complete,
3124 # since in that case our .complete() won't be called.
3125 if self.inner.isComplete():
3126 self.name = self.keyType.name + self.inner.name + "Record"
3128 def __hash__(self):
3129 return hash(self.inner)
3131 def __eq__(self, other):
3132 return isinstance(other, IDLRecordType) and self.inner == other.inner
3134 def __str__(self):
3135 return self.keyType.__str__() + self.inner.__str__() + "Record"
3137 def prettyName(self):
3138 return "record<%s, %s>" % (self.keyType.prettyName(), self.inner.prettyName())
3140 def isRecord(self):
3141 return True
3143 def isJSONType(self):
3144 return self.inner.isJSONType()
3146 def tag(self):
3147 return IDLType.Tags.record
3149 def complete(self, scope):
3150 if self.inner.isObservableArray():
3151 raise WebIDLError(
3152 "The value type of a record type must not be an ObservableArray type",
3153 [self.location, self.inner.location],
3156 self.inner = self.inner.complete(scope)
3157 self.name = self.keyType.name + self.inner.name + "Record"
3158 return self
3160 def unroll(self):
3161 # We do not unroll our inner. Just stop at ourselves. That
3162 # lets us add headers for both ourselves and our inner as
3163 # needed.
3164 return self
3166 def isDistinguishableFrom(self, other):
3167 if other.isPromise():
3168 return False
3169 if other.isUnion():
3170 # Just forward to the union; it'll deal
3171 return other.isDistinguishableFrom(self)
3172 if other.isCallback():
3173 # Let other determine if it's a LegacyTreatNonObjectAsNull callback
3174 return other.isDistinguishableFrom(self)
3175 return (
3176 other.isPrimitive()
3177 or other.isString()
3178 or other.isEnum()
3179 or other.isNonCallbackInterface()
3180 or other.isSequence()
3183 def isExposedInAllOf(self, exposureSet):
3184 return self.inner.unroll().isExposedInAllOf(exposureSet)
3187 class IDLObservableArrayType(IDLParametrizedType):
3188 __slots__ = ()
3190 def __init__(self, location, innerType):
3191 assert not innerType.isUndefined()
3192 IDLParametrizedType.__init__(self, location, None, innerType)
3194 def __hash__(self):
3195 return hash(self.inner)
3197 def __eq__(self, other):
3198 return isinstance(other, IDLObservableArrayType) and self.inner == other.inner
3200 def __str__(self):
3201 return self.inner.__str__() + "ObservableArray"
3203 def prettyName(self):
3204 return "ObservableArray<%s>" % self.inner.prettyName()
3206 def isJSONType(self):
3207 return self.inner.isJSONType()
3209 def isObservableArray(self):
3210 return True
3212 def isComplete(self):
3213 return self.name is not None
3215 def tag(self):
3216 return IDLType.Tags.observablearray
3218 def complete(self, scope):
3219 if not self.inner.isComplete():
3220 self.inner = self.inner.complete(scope)
3221 assert self.inner.isComplete()
3223 if self.inner.isDictionary():
3224 raise WebIDLError(
3225 "The inner type of an ObservableArray type must not "
3226 "be a dictionary type",
3227 [self.location, self.inner.location],
3229 if self.inner.isSequence():
3230 raise WebIDLError(
3231 "The inner type of an ObservableArray type must not "
3232 "be a sequence type",
3233 [self.location, self.inner.location],
3235 if self.inner.isRecord():
3236 raise WebIDLError(
3237 "The inner type of an ObservableArray type must not be a record type",
3238 [self.location, self.inner.location],
3240 if self.inner.isObservableArray():
3241 raise WebIDLError(
3242 "The inner type of an ObservableArray type must not "
3243 "be an ObservableArray type",
3244 [self.location, self.inner.location],
3247 self.name = self.inner.name + "ObservableArray"
3248 return self
3250 def isDistinguishableFrom(self, other):
3251 # ObservableArrays are not distinguishable from anything.
3252 return False
3255 class IDLUnionType(IDLType):
3256 __slots__ = (
3257 "memberTypes",
3258 "hasNullableType",
3259 "_dictionaryType",
3260 "flatMemberTypes",
3261 "builtin",
3264 def __init__(self, location, memberTypes):
3265 IDLType.__init__(self, location, "")
3266 self.memberTypes = memberTypes
3267 self.hasNullableType = False
3268 self._dictionaryType = None
3269 self.flatMemberTypes = None
3270 self.builtin = False
3272 def __eq__(self, other):
3273 return isinstance(other, IDLUnionType) and self.memberTypes == other.memberTypes
3275 def __hash__(self):
3276 assert self.isComplete()
3277 return self.name.__hash__()
3279 def prettyName(self):
3280 return "(" + " or ".join(m.prettyName() for m in self.memberTypes) + ")"
3282 def isUnion(self):
3283 return True
3285 def isJSONType(self):
3286 return all(m.isJSONType() for m in self.memberTypes)
3288 def includesRestrictedFloat(self):
3289 return any(t.includesRestrictedFloat() for t in self.memberTypes)
3291 def tag(self):
3292 return IDLType.Tags.union
3294 def resolveType(self, parentScope):
3295 assert isinstance(parentScope, IDLScope)
3296 for t in self.memberTypes:
3297 t.resolveType(parentScope)
3299 def isComplete(self):
3300 return self.flatMemberTypes is not None
3302 def complete(self, scope):
3303 def typeName(type):
3304 if isinstance(type, IDLNullableType):
3305 return typeName(type.inner) + "OrNull"
3306 if isinstance(type, IDLWrapperType):
3307 return typeName(type._identifier.object())
3308 if isinstance(type, IDLObjectWithIdentifier):
3309 return typeName(type.identifier)
3310 if isinstance(type, IDLBuiltinType) and type.hasAllowShared():
3311 assert type.isBufferSource()
3312 return "MaybeShared" + type.name
3313 return type.name
3315 for i, type in enumerate(self.memberTypes):
3316 if not type.isComplete():
3317 self.memberTypes[i] = type.complete(scope)
3319 self.name = "Or".join(typeName(type) for type in self.memberTypes)
3320 self.flatMemberTypes = list(self.memberTypes)
3321 i = 0
3322 while i < len(self.flatMemberTypes):
3323 if self.flatMemberTypes[i].nullable():
3324 if self.hasNullableType:
3325 raise WebIDLError(
3326 "Can't have more than one nullable types in a union",
3327 [nullableType.location, self.flatMemberTypes[i].location],
3329 if self.hasDictionaryType():
3330 raise WebIDLError(
3331 "Can't have a nullable type and a "
3332 "dictionary type in a union",
3334 self._dictionaryType.location,
3335 self.flatMemberTypes[i].location,
3338 self.hasNullableType = True
3339 nullableType = self.flatMemberTypes[i]
3340 self.flatMemberTypes[i] = self.flatMemberTypes[i].inner
3341 continue
3342 if self.flatMemberTypes[i].isDictionary():
3343 if self.hasNullableType:
3344 raise WebIDLError(
3345 "Can't have a nullable type and a "
3346 "dictionary type in a union",
3347 [nullableType.location, self.flatMemberTypes[i].location],
3349 self._dictionaryType = self.flatMemberTypes[i]
3350 self.flatMemberTypes[i].inner.needsConversionFromJS = True
3351 elif self.flatMemberTypes[i].isUnion():
3352 self.flatMemberTypes[i : i + 1] = self.flatMemberTypes[i].memberTypes
3353 continue
3354 i += 1
3356 for i, t in enumerate(self.flatMemberTypes[:-1]):
3357 for u in self.flatMemberTypes[i + 1 :]:
3358 if not t.isDistinguishableFrom(u):
3359 raise WebIDLError(
3360 "Flat member types of a union should be "
3361 "distinguishable, " + str(t) + " is not "
3362 "distinguishable from " + str(u),
3363 [self.location, t.location, u.location],
3366 return self
3368 def isDistinguishableFrom(self, other):
3369 if self.hasNullableType and other.nullable():
3370 # Can't tell which type null should become
3371 return False
3372 if other.isUnion():
3373 otherTypes = other.unroll().memberTypes
3374 else:
3375 otherTypes = [other]
3376 # For every type in otherTypes, check that it's distinguishable from
3377 # every type in our types
3378 for u in otherTypes:
3379 if any(not t.isDistinguishableFrom(u) for t in self.memberTypes):
3380 return False
3381 return True
3383 def isExposedInAllOf(self, exposureSet):
3384 # We could have different member types in different globals.
3385 # Just make sure that each thing in exposureSet has one of our member types exposed in it.
3386 for globalName in exposureSet:
3387 if not any(
3388 t.unroll().isExposedInAllOf(set([globalName]))
3389 for t in self.flatMemberTypes
3391 return False
3392 return True
3394 def hasDictionaryType(self):
3395 return self._dictionaryType is not None
3397 def hasPossiblyEmptyDictionaryType(self):
3398 return (
3399 self._dictionaryType is not None and self._dictionaryType.inner.canBeEmpty()
3402 def _getDependentObjects(self):
3403 return set(self.memberTypes)
3406 class IDLTypedefType(IDLType):
3407 __slots__ = "inner", "builtin"
3409 def __init__(self, location, innerType, name):
3410 IDLType.__init__(self, location, name)
3411 self.inner = innerType
3412 self.builtin = False
3414 def __hash__(self):
3415 return hash(self.inner)
3417 def __eq__(self, other):
3418 return isinstance(other, IDLTypedefType) and self.inner == other.inner
3420 def __str__(self):
3421 return self.name
3423 def nullable(self):
3424 return self.inner.nullable()
3426 def isPrimitive(self):
3427 return self.inner.isPrimitive()
3429 def isBoolean(self):
3430 return self.inner.isBoolean()
3432 def isNumeric(self):
3433 return self.inner.isNumeric()
3435 def isString(self):
3436 return self.inner.isString()
3438 def isByteString(self):
3439 return self.inner.isByteString()
3441 def isDOMString(self):
3442 return self.inner.isDOMString()
3444 def isUSVString(self):
3445 return self.inner.isUSVString()
3447 def isUTF8String(self):
3448 return self.inner.isUTF8String()
3450 def isJSString(self):
3451 return self.inner.isJSString()
3453 def isUndefined(self):
3454 return self.inner.isUndefined()
3456 def isJSONType(self):
3457 return self.inner.isJSONType()
3459 def isSequence(self):
3460 return self.inner.isSequence()
3462 def isRecord(self):
3463 return self.inner.isRecord()
3465 def isDictionary(self):
3466 return self.inner.isDictionary()
3468 def isArrayBuffer(self):
3469 return self.inner.isArrayBuffer()
3471 def isArrayBufferView(self):
3472 return self.inner.isArrayBufferView()
3474 def isTypedArray(self):
3475 return self.inner.isTypedArray()
3477 def isInterface(self):
3478 return self.inner.isInterface()
3480 def isCallbackInterface(self):
3481 return self.inner.isCallbackInterface()
3483 def isNonCallbackInterface(self):
3484 return self.inner.isNonCallbackInterface()
3486 def isComplete(self):
3487 return False
3489 def complete(self, parentScope):
3490 if not self.inner.isComplete():
3491 self.inner = self.inner.complete(parentScope)
3492 assert self.inner.isComplete()
3493 return self.inner
3495 # Do we need a resolveType impl? I don't think it's particularly useful....
3497 def tag(self):
3498 return self.inner.tag()
3500 def unroll(self):
3501 return self.inner.unroll()
3503 def isDistinguishableFrom(self, other):
3504 return self.inner.isDistinguishableFrom(other)
3506 def _getDependentObjects(self):
3507 return self.inner._getDependentObjects()
3509 def withExtendedAttributes(self, attrs):
3510 return IDLTypedefType(
3511 self.location, self.inner.withExtendedAttributes(attrs), self.name
3515 class IDLTypedef(IDLObjectWithIdentifier):
3516 __slots__ = ("innerType",)
3518 def __init__(self, location, parentScope, innerType, identifier):
3519 # Set self.innerType first, because IDLObjectWithIdentifier.__init__
3520 # will call our __str__, which wants to use it.
3521 self.innerType = innerType
3522 IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
3524 def __str__(self):
3525 return "Typedef %s %s" % (self.identifier.name, self.innerType)
3527 def finish(self, parentScope):
3528 if not self.innerType.isComplete():
3529 self.innerType = self.innerType.complete(parentScope)
3531 def validate(self):
3532 pass
3534 def isTypedef(self):
3535 return True
3537 def addExtendedAttributes(self, attrs):
3538 if len(attrs) != 0:
3539 raise WebIDLError(
3540 "There are no extended attributes that are allowed on typedefs",
3541 [attrs[0].location, self.location],
3544 def _getDependentObjects(self):
3545 return self.innerType._getDependentObjects()
3548 class IDLWrapperType(IDLType):
3549 __slots__ = "inner", "_identifier", "builtin"
3551 def __init__(self, location, inner):
3552 IDLType.__init__(self, location, inner.identifier.name)
3553 self.inner = inner
3554 self._identifier = inner.identifier
3555 self.builtin = False
3557 def __hash__(self):
3558 return hash(self._identifier) + hash(self.builtin)
3560 def __eq__(self, other):
3561 return (
3562 isinstance(other, IDLWrapperType)
3563 and self._identifier == other._identifier
3564 and self.builtin == other.builtin
3567 def __str__(self):
3568 return str(self.name) + " (Wrapper)"
3570 def isDictionary(self):
3571 return isinstance(self.inner, IDLDictionary)
3573 def isInterface(self):
3574 return isinstance(self.inner, IDLInterface) or isinstance(
3575 self.inner, IDLExternalInterface
3578 def isCallbackInterface(self):
3579 return self.isInterface() and self.inner.isCallback()
3581 def isNonCallbackInterface(self):
3582 return self.isInterface() and not self.inner.isCallback()
3584 def isEnum(self):
3585 return isinstance(self.inner, IDLEnum)
3587 def isJSONType(self):
3588 if self.isInterface():
3589 if self.inner.isExternal():
3590 return False
3591 iface = self.inner
3592 while iface:
3593 if any(m.isMethod() and m.isToJSON() for m in iface.members):
3594 return True
3595 iface = iface.parent
3596 return False
3597 elif self.isEnum():
3598 return True
3599 elif self.isDictionary():
3600 dictionary = self.inner
3601 while dictionary:
3602 if not all(m.type.isJSONType() for m in dictionary.members):
3603 return False
3604 dictionary = dictionary.parent
3605 return True
3606 else:
3607 raise WebIDLError(
3608 "IDLWrapperType wraps type %s that we don't know if "
3609 "is serializable" % type(self.inner),
3610 [self.location],
3613 def resolveType(self, parentScope):
3614 assert isinstance(parentScope, IDLScope)
3615 self.inner.resolve(parentScope)
3617 def isComplete(self):
3618 return True
3620 def tag(self):
3621 if self.isInterface():
3622 return IDLType.Tags.interface
3623 elif self.isEnum():
3624 return IDLType.Tags.enum
3625 elif self.isDictionary():
3626 return IDLType.Tags.dictionary
3627 else:
3628 assert False
3630 def isDistinguishableFrom(self, other):
3631 if other.isPromise():
3632 return False
3633 if other.isUnion():
3634 # Just forward to the union; it'll deal
3635 return other.isDistinguishableFrom(self)
3636 assert self.isInterface() or self.isEnum() or self.isDictionary()
3637 if self.isEnum():
3638 return (
3639 other.isUndefined()
3640 or other.isPrimitive()
3641 or other.isInterface()
3642 or other.isObject()
3643 or other.isCallback()
3644 or other.isDictionary()
3645 or other.isSequence()
3646 or other.isRecord()
3648 if self.isDictionary() and other.nullable():
3649 return False
3650 if (
3651 other.isPrimitive()
3652 or other.isString()
3653 or other.isEnum()
3654 or other.isSequence()
3656 return True
3658 # If this needs to handle other dictionary-like types we probably need
3659 # some additional checks first.
3660 assert self.isDictionaryLike() == (
3661 self.isDictionary() or self.isCallbackInterface()
3663 if self.isDictionaryLike():
3664 if other.isCallback():
3665 # Let other determine if it's a LegacyTreatNonObjectAsNull callback
3666 return other.isDistinguishableFrom(self)
3668 assert (
3669 other.isNonCallbackInterface()
3670 or other.isAny()
3671 or other.isUndefined()
3672 or other.isObject()
3673 or other.isDictionaryLike()
3675 # At this point, dictionary-like (for 'self') and interface-like
3676 # (for 'other') are the only two that are distinguishable.
3677 # any is the union of all non-union types, so it's not distinguishable
3678 # from other unions (because it is a union itself), or from all
3679 # non-union types (because it has all of them as its members).
3680 return other.isNonCallbackInterface()
3682 assert self.isNonCallbackInterface()
3684 if other.isUndefined() or other.isDictionaryLike() or other.isCallback():
3685 return True
3687 if other.isNonCallbackInterface():
3688 if other.isSpiderMonkeyInterface():
3689 # Just let |other| handle things
3690 return other.isDistinguishableFrom(self)
3692 assert self.isGeckoInterface() and other.isGeckoInterface()
3693 if self.inner.isExternal() or other.unroll().inner.isExternal():
3694 return self != other
3695 return (
3696 len(
3697 self.inner.interfacesBasedOnSelf
3698 & other.unroll().inner.interfacesBasedOnSelf
3700 == 0
3703 # Not much else |other| can be.
3704 # any is the union of all non-union types, so it's not distinguishable
3705 # from other unions (because it is a union itself), or from all
3706 # non-union types (because it has all of them as its members).
3707 assert other.isAny() or other.isObject()
3708 return False
3710 def isExposedInAllOf(self, exposureSet):
3711 if not self.isInterface():
3712 return True
3713 iface = self.inner
3714 if iface.isExternal():
3715 # Let's say true, so we don't have to implement exposure mixins on
3716 # external interfaces and sprinkle [Exposed=Window] on every single
3717 # external interface declaration.
3718 return True
3719 return iface.exposureSet.issuperset(exposureSet)
3721 def _getDependentObjects(self):
3722 # NB: The codegen for an interface type depends on
3723 # a) That the identifier is in fact an interface (as opposed to
3724 # a dictionary or something else).
3725 # b) The native type of the interface.
3726 # If we depend on the interface object we will also depend on
3727 # anything the interface depends on which is undesirable. We
3728 # considered implementing a dependency just on the interface type
3729 # file, but then every modification to an interface would cause this
3730 # to be regenerated which is still undesirable. We decided not to
3731 # depend on anything, reasoning that:
3732 # 1) Changing the concrete type of the interface requires modifying
3733 # Bindings.conf, which is still a global dependency.
3734 # 2) Changing an interface to a dictionary (or vice versa) with the
3735 # same identifier should be incredibly rare.
3737 # On the other hand, if our type is a dictionary, we should
3738 # depend on it, because the member types of a dictionary
3739 # affect whether a method taking the dictionary as an argument
3740 # takes a JSContext* argument or not.
3741 if self.isDictionary():
3742 return set([self.inner])
3743 return set()
3746 class IDLPromiseType(IDLParametrizedType):
3747 __slots__ = ()
3749 def __init__(self, location, innerType):
3750 IDLParametrizedType.__init__(self, location, "Promise", innerType)
3752 def __hash__(self):
3753 return hash(self.promiseInnerType())
3755 def __eq__(self, other):
3756 return (
3757 isinstance(other, IDLPromiseType)
3758 and self.promiseInnerType() == other.promiseInnerType()
3761 def __str__(self):
3762 return self.inner.__str__() + "Promise"
3764 def prettyName(self):
3765 return "Promise<%s>" % self.inner.prettyName()
3767 def isPromise(self):
3768 return True
3770 def promiseInnerType(self):
3771 return self.inner
3773 def tag(self):
3774 return IDLType.Tags.promise
3776 def complete(self, scope):
3777 if self.inner.isObservableArray():
3778 raise WebIDLError(
3779 "The inner type of a promise type must not be an ObservableArray type",
3780 [self.location, self.inner.location],
3783 self.inner = self.promiseInnerType().complete(scope)
3784 return self
3786 def unroll(self):
3787 # We do not unroll our inner. Just stop at ourselves. That
3788 # lets us add headers for both ourselves and our inner as
3789 # needed.
3790 return self
3792 def isDistinguishableFrom(self, other):
3793 # Promises are not distinguishable from anything.
3794 return False
3796 def isExposedInAllOf(self, exposureSet):
3797 # Check the internal type
3798 return self.promiseInnerType().unroll().isExposedInAllOf(exposureSet)
3801 class IDLBuiltinType(IDLType):
3802 Types = enum(
3803 # The integer types
3804 "byte",
3805 "octet",
3806 "short",
3807 "unsigned_short",
3808 "long",
3809 "unsigned_long",
3810 "long_long",
3811 "unsigned_long_long",
3812 # Additional primitive types
3813 "boolean",
3814 "unrestricted_float",
3815 "float",
3816 "unrestricted_double",
3817 # IMPORTANT: "double" must be the last primitive type listed
3818 "double",
3819 # Other types
3820 "any",
3821 "undefined",
3822 "domstring",
3823 "bytestring",
3824 "usvstring",
3825 "utf8string",
3826 "jsstring",
3827 "object",
3828 # Funny stuff
3829 "ArrayBuffer",
3830 "ArrayBufferView",
3831 "Int8Array",
3832 "Uint8Array",
3833 "Uint8ClampedArray",
3834 "Int16Array",
3835 "Uint16Array",
3836 "Int32Array",
3837 "Uint32Array",
3838 "Float32Array",
3839 "Float64Array",
3842 TagLookup = {
3843 Types.byte: IDLType.Tags.int8,
3844 Types.octet: IDLType.Tags.uint8,
3845 Types.short: IDLType.Tags.int16,
3846 Types.unsigned_short: IDLType.Tags.uint16,
3847 Types.long: IDLType.Tags.int32,
3848 Types.unsigned_long: IDLType.Tags.uint32,
3849 Types.long_long: IDLType.Tags.int64,
3850 Types.unsigned_long_long: IDLType.Tags.uint64,
3851 Types.boolean: IDLType.Tags.bool,
3852 Types.unrestricted_float: IDLType.Tags.unrestricted_float,
3853 Types.float: IDLType.Tags.float,
3854 Types.unrestricted_double: IDLType.Tags.unrestricted_double,
3855 Types.double: IDLType.Tags.double,
3856 Types.any: IDLType.Tags.any,
3857 Types.undefined: IDLType.Tags.undefined,
3858 Types.domstring: IDLType.Tags.domstring,
3859 Types.bytestring: IDLType.Tags.bytestring,
3860 Types.usvstring: IDLType.Tags.usvstring,
3861 Types.utf8string: IDLType.Tags.utf8string,
3862 Types.jsstring: IDLType.Tags.jsstring,
3863 Types.object: IDLType.Tags.object,
3864 Types.ArrayBuffer: IDLType.Tags.interface,
3865 Types.ArrayBufferView: IDLType.Tags.interface,
3866 Types.Int8Array: IDLType.Tags.interface,
3867 Types.Uint8Array: IDLType.Tags.interface,
3868 Types.Uint8ClampedArray: IDLType.Tags.interface,
3869 Types.Int16Array: IDLType.Tags.interface,
3870 Types.Uint16Array: IDLType.Tags.interface,
3871 Types.Int32Array: IDLType.Tags.interface,
3872 Types.Uint32Array: IDLType.Tags.interface,
3873 Types.Float32Array: IDLType.Tags.interface,
3874 Types.Float64Array: IDLType.Tags.interface,
3877 PrettyNames = {
3878 Types.byte: "byte",
3879 Types.octet: "octet",
3880 Types.short: "short",
3881 Types.unsigned_short: "unsigned short",
3882 Types.long: "long",
3883 Types.unsigned_long: "unsigned long",
3884 Types.long_long: "long long",
3885 Types.unsigned_long_long: "unsigned long long",
3886 Types.boolean: "boolean",
3887 Types.unrestricted_float: "unrestricted float",
3888 Types.float: "float",
3889 Types.unrestricted_double: "unrestricted double",
3890 Types.double: "double",
3891 Types.any: "any",
3892 Types.undefined: "undefined",
3893 Types.domstring: "DOMString",
3894 Types.bytestring: "ByteString",
3895 Types.usvstring: "USVString",
3896 Types.utf8string: "USVString", # That's what it is in spec terms
3897 Types.jsstring: "USVString", # Again, that's what it is in spec terms
3898 Types.object: "object",
3899 Types.ArrayBuffer: "ArrayBuffer",
3900 Types.ArrayBufferView: "ArrayBufferView",
3901 Types.Int8Array: "Int8Array",
3902 Types.Uint8Array: "Uint8Array",
3903 Types.Uint8ClampedArray: "Uint8ClampedArray",
3904 Types.Int16Array: "Int16Array",
3905 Types.Uint16Array: "Uint16Array",
3906 Types.Int32Array: "Int32Array",
3907 Types.Uint32Array: "Uint32Array",
3908 Types.Float32Array: "Float32Array",
3909 Types.Float64Array: "Float64Array",
3912 __slots__ = (
3913 "_typeTag",
3914 "_clamped",
3915 "_rangeEnforced",
3916 "_withLegacyNullToEmptyString",
3917 "_withAllowShared",
3920 def __init__(
3921 self,
3922 location,
3923 name,
3924 type,
3925 clamp=False,
3926 enforceRange=False,
3927 legacyNullToEmptyString=False,
3928 allowShared=False,
3929 attrLocation=[],
3932 The mutually exclusive clamp/enforceRange/legacyNullToEmptyString/allowShared arguments
3933 are used to create instances of this type with the appropriate attributes attached. Use
3934 .clamped(), .rangeEnforced(), .withLegacyNullToEmptyString() and .withAllowShared().
3936 attrLocation is an array of source locations of these attributes for error reporting.
3938 IDLType.__init__(self, location, name)
3939 self.builtin = True
3940 self._typeTag = type
3941 self._clamped = None
3942 self._rangeEnforced = None
3943 self._withLegacyNullToEmptyString = None
3944 self._withAllowShared = None
3945 if self.isInteger():
3946 if clamp:
3947 self._clamp = True
3948 self.name = "Clamped" + self.name
3949 self._extendedAttrDict["Clamp"] = True
3950 elif enforceRange:
3951 self._enforceRange = True
3952 self.name = "RangeEnforced" + self.name
3953 self._extendedAttrDict["EnforceRange"] = True
3954 elif clamp or enforceRange:
3955 raise WebIDLError(
3956 "Non-integer types cannot be [Clamp] or [EnforceRange]", attrLocation
3958 if self.isDOMString() or self.isUTF8String():
3959 if legacyNullToEmptyString:
3960 self.legacyNullToEmptyString = True
3961 self.name = "NullIsEmpty" + self.name
3962 self._extendedAttrDict["LegacyNullToEmptyString"] = True
3963 elif legacyNullToEmptyString:
3964 raise WebIDLError(
3965 "Non-string types cannot be [LegacyNullToEmptyString]", attrLocation
3967 if self.isBufferSource():
3968 if allowShared:
3969 self._allowShared = True
3970 self._extendedAttrDict["AllowShared"] = True
3971 elif allowShared:
3972 raise WebIDLError(
3973 "Types that are not buffer source types cannot be [AllowShared]",
3974 attrLocation,
3977 def __str__(self):
3978 if self._allowShared:
3979 assert self.isBufferSource()
3980 return "MaybeShared" + str(self.name)
3981 return str(self.name)
3983 def prettyName(self):
3984 return IDLBuiltinType.PrettyNames[self._typeTag]
3986 def clamped(self, attrLocation):
3987 if not self._clamped:
3988 self._clamped = IDLBuiltinType(
3989 self.location,
3990 self.name,
3991 self._typeTag,
3992 clamp=True,
3993 attrLocation=attrLocation,
3995 return self._clamped
3997 def rangeEnforced(self, attrLocation):
3998 if not self._rangeEnforced:
3999 self._rangeEnforced = IDLBuiltinType(
4000 self.location,
4001 self.name,
4002 self._typeTag,
4003 enforceRange=True,
4004 attrLocation=attrLocation,
4006 return self._rangeEnforced
4008 def withLegacyNullToEmptyString(self, attrLocation):
4009 if not self._withLegacyNullToEmptyString:
4010 self._withLegacyNullToEmptyString = IDLBuiltinType(
4011 self.location,
4012 self.name,
4013 self._typeTag,
4014 legacyNullToEmptyString=True,
4015 attrLocation=attrLocation,
4017 return self._withLegacyNullToEmptyString
4019 def withAllowShared(self, attrLocation):
4020 if not self._withAllowShared:
4021 self._withAllowShared = IDLBuiltinType(
4022 self.location,
4023 self.name,
4024 self._typeTag,
4025 allowShared=True,
4026 attrLocation=attrLocation,
4028 return self._withAllowShared
4030 def isPrimitive(self):
4031 return self._typeTag <= IDLBuiltinType.Types.double
4033 def isBoolean(self):
4034 return self._typeTag == IDLBuiltinType.Types.boolean
4036 def isUndefined(self):
4037 return self._typeTag == IDLBuiltinType.Types.undefined
4039 def isNumeric(self):
4040 return self.isPrimitive() and not self.isBoolean()
4042 def isString(self):
4043 return (
4044 self._typeTag == IDLBuiltinType.Types.domstring
4045 or self._typeTag == IDLBuiltinType.Types.bytestring
4046 or self._typeTag == IDLBuiltinType.Types.usvstring
4047 or self._typeTag == IDLBuiltinType.Types.utf8string
4048 or self._typeTag == IDLBuiltinType.Types.jsstring
4051 def isByteString(self):
4052 return self._typeTag == IDLBuiltinType.Types.bytestring
4054 def isDOMString(self):
4055 return self._typeTag == IDLBuiltinType.Types.domstring
4057 def isUSVString(self):
4058 return self._typeTag == IDLBuiltinType.Types.usvstring
4060 def isUTF8String(self):
4061 return self._typeTag == IDLBuiltinType.Types.utf8string
4063 def isJSString(self):
4064 return self._typeTag == IDLBuiltinType.Types.jsstring
4066 def isInteger(self):
4067 return self._typeTag <= IDLBuiltinType.Types.unsigned_long_long
4069 def isArrayBuffer(self):
4070 return self._typeTag == IDLBuiltinType.Types.ArrayBuffer
4072 def isArrayBufferView(self):
4073 return self._typeTag == IDLBuiltinType.Types.ArrayBufferView
4075 def isTypedArray(self):
4076 return (
4077 self._typeTag >= IDLBuiltinType.Types.Int8Array
4078 and self._typeTag <= IDLBuiltinType.Types.Float64Array
4081 def isInterface(self):
4082 # TypedArray things are interface types per the TypedArray spec,
4083 # but we handle them as builtins because SpiderMonkey implements
4084 # all of it internally.
4085 return self.isArrayBuffer() or self.isArrayBufferView() or self.isTypedArray()
4087 def isNonCallbackInterface(self):
4088 # All the interfaces we can be are non-callback
4089 return self.isInterface()
4091 def isFloat(self):
4092 return (
4093 self._typeTag == IDLBuiltinType.Types.float
4094 or self._typeTag == IDLBuiltinType.Types.double
4095 or self._typeTag == IDLBuiltinType.Types.unrestricted_float
4096 or self._typeTag == IDLBuiltinType.Types.unrestricted_double
4099 def isUnrestricted(self):
4100 assert self.isFloat()
4101 return (
4102 self._typeTag == IDLBuiltinType.Types.unrestricted_float
4103 or self._typeTag == IDLBuiltinType.Types.unrestricted_double
4106 def isJSONType(self):
4107 return self.isPrimitive() or self.isString() or self.isObject()
4109 def includesRestrictedFloat(self):
4110 return self.isFloat() and not self.isUnrestricted()
4112 def tag(self):
4113 return IDLBuiltinType.TagLookup[self._typeTag]
4115 def isDistinguishableFrom(self, other):
4116 if other.isPromise():
4117 return False
4118 if other.isUnion():
4119 # Just forward to the union; it'll deal
4120 return other.isDistinguishableFrom(self)
4121 if self.isUndefined():
4122 return not (other.isUndefined() or other.isDictionaryLike())
4123 if self.isPrimitive():
4124 if (
4125 other.isUndefined()
4126 or other.isString()
4127 or other.isEnum()
4128 or other.isInterface()
4129 or other.isObject()
4130 or other.isCallback()
4131 or other.isDictionary()
4132 or other.isSequence()
4133 or other.isRecord()
4135 return True
4136 if self.isBoolean():
4137 return other.isNumeric()
4138 assert self.isNumeric()
4139 return other.isBoolean()
4140 if self.isString():
4141 return (
4142 other.isUndefined()
4143 or other.isPrimitive()
4144 or other.isInterface()
4145 or other.isObject()
4146 or other.isCallback()
4147 or other.isDictionary()
4148 or other.isSequence()
4149 or other.isRecord()
4151 if self.isAny():
4152 # Can't tell "any" apart from anything
4153 return False
4154 if self.isObject():
4155 return (
4156 other.isUndefined()
4157 or other.isPrimitive()
4158 or other.isString()
4159 or other.isEnum()
4161 # Not much else we could be!
4162 assert self.isSpiderMonkeyInterface()
4163 # Like interfaces, but we know we're not a callback
4164 return (
4165 other.isUndefined()
4166 or other.isPrimitive()
4167 or other.isString()
4168 or other.isEnum()
4169 or other.isCallback()
4170 or other.isDictionary()
4171 or other.isSequence()
4172 or other.isRecord()
4173 or (
4174 other.isInterface()
4175 and (
4176 # ArrayBuffer is distinguishable from everything
4177 # that's not an ArrayBuffer or a callback interface
4178 (self.isArrayBuffer() and not other.isArrayBuffer())
4180 # ArrayBufferView is distinguishable from everything
4181 # that's not an ArrayBufferView or typed array.
4183 self.isArrayBufferView()
4184 and not other.isArrayBufferView()
4185 and not other.isTypedArray()
4188 # Typed arrays are distinguishable from everything
4189 # except ArrayBufferView and the same type of typed
4190 # array
4192 self.isTypedArray()
4193 and not other.isArrayBufferView()
4194 and not (other.isTypedArray() and other.name == self.name)
4200 def _getDependentObjects(self):
4201 return set()
4203 def withExtendedAttributes(self, attrs):
4204 ret = self
4205 for attribute in attrs:
4206 identifier = attribute.identifier()
4207 if identifier == "Clamp":
4208 if not attribute.noArguments():
4209 raise WebIDLError(
4210 "[Clamp] must take no arguments", [attribute.location]
4212 if ret.hasEnforceRange() or self._enforceRange:
4213 raise WebIDLError(
4214 "[EnforceRange] and [Clamp] are mutually exclusive",
4215 [self.location, attribute.location],
4217 ret = self.clamped([self.location, attribute.location])
4218 elif identifier == "EnforceRange":
4219 if not attribute.noArguments():
4220 raise WebIDLError(
4221 "[EnforceRange] must take no arguments", [attribute.location]
4223 if ret.hasClamp() or self._clamp:
4224 raise WebIDLError(
4225 "[EnforceRange] and [Clamp] are mutually exclusive",
4226 [self.location, attribute.location],
4228 ret = self.rangeEnforced([self.location, attribute.location])
4229 elif identifier == "LegacyNullToEmptyString":
4230 if not (self.isDOMString() or self.isUTF8String()):
4231 raise WebIDLError(
4232 "[LegacyNullToEmptyString] only allowed on DOMStrings and UTF8Strings",
4233 [self.location, attribute.location],
4235 assert not self.nullable()
4236 if attribute.hasValue():
4237 raise WebIDLError(
4238 "[LegacyNullToEmptyString] must take no identifier argument",
4239 [attribute.location],
4241 ret = self.withLegacyNullToEmptyString(
4242 [self.location, attribute.location]
4244 elif identifier == "AllowShared":
4245 if not attribute.noArguments():
4246 raise WebIDLError(
4247 "[AllowShared] must take no arguments", [attribute.location]
4249 if not self.isBufferSource():
4250 raise WebIDLError(
4251 "[AllowShared] only allowed on buffer source types",
4252 [self.location, attribute.location],
4254 ret = self.withAllowShared([self.location, attribute.location])
4256 else:
4257 raise WebIDLError(
4258 "Unhandled extended attribute on type",
4259 [self.location, attribute.location],
4261 return ret
4264 BuiltinTypes = {
4265 IDLBuiltinType.Types.byte: IDLBuiltinType(
4266 BuiltinLocation("<builtin type>"), "Byte", IDLBuiltinType.Types.byte
4268 IDLBuiltinType.Types.octet: IDLBuiltinType(
4269 BuiltinLocation("<builtin type>"), "Octet", IDLBuiltinType.Types.octet
4271 IDLBuiltinType.Types.short: IDLBuiltinType(
4272 BuiltinLocation("<builtin type>"), "Short", IDLBuiltinType.Types.short
4274 IDLBuiltinType.Types.unsigned_short: IDLBuiltinType(
4275 BuiltinLocation("<builtin type>"),
4276 "UnsignedShort",
4277 IDLBuiltinType.Types.unsigned_short,
4279 IDLBuiltinType.Types.long: IDLBuiltinType(
4280 BuiltinLocation("<builtin type>"), "Long", IDLBuiltinType.Types.long
4282 IDLBuiltinType.Types.unsigned_long: IDLBuiltinType(
4283 BuiltinLocation("<builtin type>"),
4284 "UnsignedLong",
4285 IDLBuiltinType.Types.unsigned_long,
4287 IDLBuiltinType.Types.long_long: IDLBuiltinType(
4288 BuiltinLocation("<builtin type>"), "LongLong", IDLBuiltinType.Types.long_long
4290 IDLBuiltinType.Types.unsigned_long_long: IDLBuiltinType(
4291 BuiltinLocation("<builtin type>"),
4292 "UnsignedLongLong",
4293 IDLBuiltinType.Types.unsigned_long_long,
4295 IDLBuiltinType.Types.undefined: IDLBuiltinType(
4296 BuiltinLocation("<builtin type>"), "Undefined", IDLBuiltinType.Types.undefined
4298 IDLBuiltinType.Types.boolean: IDLBuiltinType(
4299 BuiltinLocation("<builtin type>"), "Boolean", IDLBuiltinType.Types.boolean
4301 IDLBuiltinType.Types.float: IDLBuiltinType(
4302 BuiltinLocation("<builtin type>"), "Float", IDLBuiltinType.Types.float
4304 IDLBuiltinType.Types.unrestricted_float: IDLBuiltinType(
4305 BuiltinLocation("<builtin type>"),
4306 "UnrestrictedFloat",
4307 IDLBuiltinType.Types.unrestricted_float,
4309 IDLBuiltinType.Types.double: IDLBuiltinType(
4310 BuiltinLocation("<builtin type>"), "Double", IDLBuiltinType.Types.double
4312 IDLBuiltinType.Types.unrestricted_double: IDLBuiltinType(
4313 BuiltinLocation("<builtin type>"),
4314 "UnrestrictedDouble",
4315 IDLBuiltinType.Types.unrestricted_double,
4317 IDLBuiltinType.Types.any: IDLBuiltinType(
4318 BuiltinLocation("<builtin type>"), "Any", IDLBuiltinType.Types.any
4320 IDLBuiltinType.Types.domstring: IDLBuiltinType(
4321 BuiltinLocation("<builtin type>"), "String", IDLBuiltinType.Types.domstring
4323 IDLBuiltinType.Types.bytestring: IDLBuiltinType(
4324 BuiltinLocation("<builtin type>"), "ByteString", IDLBuiltinType.Types.bytestring
4326 IDLBuiltinType.Types.usvstring: IDLBuiltinType(
4327 BuiltinLocation("<builtin type>"), "USVString", IDLBuiltinType.Types.usvstring
4329 IDLBuiltinType.Types.utf8string: IDLBuiltinType(
4330 BuiltinLocation("<builtin type>"), "UTF8String", IDLBuiltinType.Types.utf8string
4332 IDLBuiltinType.Types.jsstring: IDLBuiltinType(
4333 BuiltinLocation("<builtin type>"), "JSString", IDLBuiltinType.Types.jsstring
4335 IDLBuiltinType.Types.object: IDLBuiltinType(
4336 BuiltinLocation("<builtin type>"), "Object", IDLBuiltinType.Types.object
4338 IDLBuiltinType.Types.ArrayBuffer: IDLBuiltinType(
4339 BuiltinLocation("<builtin type>"),
4340 "ArrayBuffer",
4341 IDLBuiltinType.Types.ArrayBuffer,
4343 IDLBuiltinType.Types.ArrayBufferView: IDLBuiltinType(
4344 BuiltinLocation("<builtin type>"),
4345 "ArrayBufferView",
4346 IDLBuiltinType.Types.ArrayBufferView,
4348 IDLBuiltinType.Types.Int8Array: IDLBuiltinType(
4349 BuiltinLocation("<builtin type>"), "Int8Array", IDLBuiltinType.Types.Int8Array
4351 IDLBuiltinType.Types.Uint8Array: IDLBuiltinType(
4352 BuiltinLocation("<builtin type>"), "Uint8Array", IDLBuiltinType.Types.Uint8Array
4354 IDLBuiltinType.Types.Uint8ClampedArray: IDLBuiltinType(
4355 BuiltinLocation("<builtin type>"),
4356 "Uint8ClampedArray",
4357 IDLBuiltinType.Types.Uint8ClampedArray,
4359 IDLBuiltinType.Types.Int16Array: IDLBuiltinType(
4360 BuiltinLocation("<builtin type>"), "Int16Array", IDLBuiltinType.Types.Int16Array
4362 IDLBuiltinType.Types.Uint16Array: IDLBuiltinType(
4363 BuiltinLocation("<builtin type>"),
4364 "Uint16Array",
4365 IDLBuiltinType.Types.Uint16Array,
4367 IDLBuiltinType.Types.Int32Array: IDLBuiltinType(
4368 BuiltinLocation("<builtin type>"), "Int32Array", IDLBuiltinType.Types.Int32Array
4370 IDLBuiltinType.Types.Uint32Array: IDLBuiltinType(
4371 BuiltinLocation("<builtin type>"),
4372 "Uint32Array",
4373 IDLBuiltinType.Types.Uint32Array,
4375 IDLBuiltinType.Types.Float32Array: IDLBuiltinType(
4376 BuiltinLocation("<builtin type>"),
4377 "Float32Array",
4378 IDLBuiltinType.Types.Float32Array,
4380 IDLBuiltinType.Types.Float64Array: IDLBuiltinType(
4381 BuiltinLocation("<builtin type>"),
4382 "Float64Array",
4383 IDLBuiltinType.Types.Float64Array,
4388 integerTypeSizes = {
4389 IDLBuiltinType.Types.byte: (-128, 127),
4390 IDLBuiltinType.Types.octet: (0, 255),
4391 IDLBuiltinType.Types.short: (-32768, 32767),
4392 IDLBuiltinType.Types.unsigned_short: (0, 65535),
4393 IDLBuiltinType.Types.long: (-2147483648, 2147483647),
4394 IDLBuiltinType.Types.unsigned_long: (0, 4294967295),
4395 IDLBuiltinType.Types.long_long: (-9223372036854775808, 9223372036854775807),
4396 IDLBuiltinType.Types.unsigned_long_long: (0, 18446744073709551615),
4400 def matchIntegerValueToType(value):
4401 for type, extremes in integerTypeSizes.items():
4402 (min, max) = extremes
4403 if value <= max and value >= min:
4404 return BuiltinTypes[type]
4406 return None
4409 class NoCoercionFoundError(WebIDLError):
4411 A class we use to indicate generic coercion failures because none of the
4412 types worked out in IDLValue.coerceToType.
4416 class IDLValue(IDLObject):
4417 __slots__ = (
4418 "type",
4419 "value",
4422 def __init__(self, location, type, value):
4423 IDLObject.__init__(self, location)
4424 self.type = type
4425 assert isinstance(type, IDLType)
4427 self.value = value
4429 def coerceToType(self, type, location):
4430 if type == self.type:
4431 return self # Nothing to do
4433 # We first check for unions to ensure that even if the union is nullable
4434 # we end up with the right flat member type, not the union's type.
4435 if type.isUnion():
4436 # We use the flat member types here, because if we have a nullable
4437 # member type, or a nested union, we want the type the value
4438 # actually coerces to, not the nullable or nested union type.
4439 for subtype in type.unroll().flatMemberTypes:
4440 try:
4441 coercedValue = self.coerceToType(subtype, location)
4442 # Create a new IDLValue to make sure that we have the
4443 # correct float/double type. This is necessary because we
4444 # use the value's type when it is a default value of a
4445 # union, and the union cares about the exact float type.
4446 return IDLValue(self.location, subtype, coercedValue.value)
4447 except Exception as e:
4448 # Make sure to propagate out WebIDLErrors that are not the
4449 # generic "hey, we could not coerce to this type at all"
4450 # exception, because those are specific "coercion failed for
4451 # reason X" exceptions. Note that we want to swallow
4452 # non-WebIDLErrors here, because those can just happen if
4453 # "type" is not something that can have a default value at
4454 # all.
4455 if isinstance(e, WebIDLError) and not isinstance(
4456 e, NoCoercionFoundError
4458 raise e
4460 # If the type allows null, rerun this matching on the inner type, except
4461 # nullable enums. We handle those specially, because we want our
4462 # default string values to stay strings even when assigned to a nullable
4463 # enum.
4464 elif type.nullable() and not type.isEnum():
4465 innerValue = self.coerceToType(type.inner, location)
4466 return IDLValue(self.location, type, innerValue.value)
4468 elif self.type.isInteger() and type.isInteger():
4469 # We're both integer types. See if we fit.
4471 (min, max) = integerTypeSizes[type._typeTag]
4472 if self.value <= max and self.value >= min:
4473 # Promote
4474 return IDLValue(self.location, type, self.value)
4475 else:
4476 raise WebIDLError(
4477 "Value %s is out of range for type %s." % (self.value, type),
4478 [location],
4480 elif self.type.isInteger() and type.isFloat():
4481 # Convert an integer literal into float
4482 if -(2**24) <= self.value <= 2**24:
4483 return IDLValue(self.location, type, float(self.value))
4484 else:
4485 raise WebIDLError(
4486 "Converting value %s to %s will lose precision."
4487 % (self.value, type),
4488 [location],
4490 elif self.type.isString() and type.isEnum():
4491 # Just keep our string, but make sure it's a valid value for this enum
4492 enum = type.unroll().inner
4493 if self.value not in enum.values():
4494 raise WebIDLError(
4495 "'%s' is not a valid default value for enum %s"
4496 % (self.value, enum.identifier.name),
4497 [location, enum.location],
4499 return self
4500 elif self.type.isFloat() and type.isFloat():
4501 if not type.isUnrestricted() and (
4502 self.value == float("inf")
4503 or self.value == float("-inf")
4504 or math.isnan(self.value)
4506 raise WebIDLError(
4507 "Trying to convert unrestricted value %s to non-unrestricted"
4508 % self.value,
4509 [location],
4511 return IDLValue(self.location, type, self.value)
4512 elif self.type.isString() and type.isUSVString():
4513 # Allow USVStrings to use default value just like
4514 # DOMString. No coercion is required in this case as Codegen.py
4515 # treats USVString just like DOMString, but with an
4516 # extra normalization step.
4517 assert self.type.isDOMString()
4518 return self
4519 elif self.type.isString() and (
4520 type.isByteString() or type.isJSString() or type.isUTF8String()
4522 # Allow ByteStrings, UTF8String, and JSStrings to use a default
4523 # value like DOMString.
4524 # No coercion is required as Codegen.py will handle the
4525 # extra steps. We want to make sure that our string contains
4526 # only valid characters, so we check that here.
4527 valid_ascii_lit = (
4528 " " + string.ascii_letters + string.digits + string.punctuation
4530 for idx, c in enumerate(self.value):
4531 if c not in valid_ascii_lit:
4532 raise WebIDLError(
4533 "Coercing this string literal %s to a ByteString is not supported yet. "
4534 "Coercion failed due to an unsupported byte %d at index %d."
4535 % (self.value.__repr__(), ord(c), idx),
4536 [location],
4539 return IDLValue(self.location, type, self.value)
4540 elif self.type.isDOMString() and type.legacyNullToEmptyString:
4541 # LegacyNullToEmptyString is a different type for resolution reasons,
4542 # however once you have a value it doesn't matter
4543 return self
4545 raise NoCoercionFoundError(
4546 "Cannot coerce type %s to type %s." % (self.type, type), [location]
4549 def _getDependentObjects(self):
4550 return set()
4553 class IDLNullValue(IDLObject):
4554 __slots__ = "type", "value"
4556 def __init__(self, location):
4557 IDLObject.__init__(self, location)
4558 self.type = None
4559 self.value = None
4561 def coerceToType(self, type, location):
4562 if (
4563 not isinstance(type, IDLNullableType)
4564 and not (type.isUnion() and type.hasNullableType)
4565 and not type.isAny()
4567 raise WebIDLError("Cannot coerce null value to type %s." % type, [location])
4569 nullValue = IDLNullValue(self.location)
4570 if type.isUnion() and not type.nullable() and type.hasDictionaryType():
4571 # We're actually a default value for the union's dictionary member.
4572 # Use its type.
4573 for t in type.flatMemberTypes:
4574 if t.isDictionary():
4575 nullValue.type = t
4576 return nullValue
4577 nullValue.type = type
4578 return nullValue
4580 def _getDependentObjects(self):
4581 return set()
4584 class IDLEmptySequenceValue(IDLObject):
4585 __slots__ = "type", "value"
4587 def __init__(self, location):
4588 IDLObject.__init__(self, location)
4589 self.type = None
4590 self.value = None
4592 def coerceToType(self, type, location):
4593 if type.isUnion():
4594 # We use the flat member types here, because if we have a nullable
4595 # member type, or a nested union, we want the type the value
4596 # actually coerces to, not the nullable or nested union type.
4597 for subtype in type.unroll().flatMemberTypes:
4598 try:
4599 return self.coerceToType(subtype, location)
4600 except Exception:
4601 pass
4603 if not type.isSequence():
4604 raise WebIDLError(
4605 "Cannot coerce empty sequence value to type %s." % type, [location]
4608 emptySequenceValue = IDLEmptySequenceValue(self.location)
4609 emptySequenceValue.type = type
4610 return emptySequenceValue
4612 def _getDependentObjects(self):
4613 return set()
4616 class IDLDefaultDictionaryValue(IDLObject):
4617 __slots__ = "type", "value"
4619 def __init__(self, location):
4620 IDLObject.__init__(self, location)
4621 self.type = None
4622 self.value = None
4624 def coerceToType(self, type, location):
4625 if type.isUnion():
4626 # We use the flat member types here, because if we have a nullable
4627 # member type, or a nested union, we want the type the value
4628 # actually coerces to, not the nullable or nested union type.
4629 for subtype in type.unroll().flatMemberTypes:
4630 try:
4631 return self.coerceToType(subtype, location)
4632 except Exception:
4633 pass
4635 if not type.isDictionary():
4636 raise WebIDLError(
4637 "Cannot coerce default dictionary value to type %s." % type, [location]
4640 defaultDictionaryValue = IDLDefaultDictionaryValue(self.location)
4641 defaultDictionaryValue.type = type
4642 return defaultDictionaryValue
4644 def _getDependentObjects(self):
4645 return set()
4648 class IDLUndefinedValue(IDLObject):
4649 __slots__ = "type", "value"
4651 def __init__(self, location):
4652 IDLObject.__init__(self, location)
4653 self.type = None
4654 self.value = None
4656 def coerceToType(self, type, location):
4657 if not type.isAny():
4658 raise WebIDLError(
4659 "Cannot coerce undefined value to type %s." % type, [location]
4662 undefinedValue = IDLUndefinedValue(self.location)
4663 undefinedValue.type = type
4664 return undefinedValue
4666 def _getDependentObjects(self):
4667 return set()
4670 class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
4671 Tags = enum(
4672 "Const", "Attr", "Method", "MaplikeOrSetlike", "AsyncIterable", "Iterable"
4675 Special = enum("Static", "Stringifier")
4677 AffectsValues = ("Nothing", "Everything")
4678 DependsOnValues = ("Nothing", "DOMState", "DeviceState", "Everything")
4680 # no slots : multiple inheritance
4681 def __init__(self, location, identifier, tag, extendedAttrDict=None):
4682 IDLObjectWithIdentifier.__init__(self, location, None, identifier)
4683 IDLExposureMixins.__init__(self, location)
4684 self.tag = tag
4685 if extendedAttrDict is None:
4686 self._extendedAttrDict = {}
4687 else:
4688 self._extendedAttrDict = extendedAttrDict
4690 def isMethod(self):
4691 return self.tag == IDLInterfaceMember.Tags.Method
4693 def isAttr(self):
4694 return self.tag == IDLInterfaceMember.Tags.Attr
4696 def isConst(self):
4697 return self.tag == IDLInterfaceMember.Tags.Const
4699 def isMaplikeOrSetlikeOrIterable(self):
4700 return (
4701 self.tag == IDLInterfaceMember.Tags.MaplikeOrSetlike
4702 or self.tag == IDLInterfaceMember.Tags.AsyncIterable
4703 or self.tag == IDLInterfaceMember.Tags.Iterable
4706 def isMaplikeOrSetlike(self):
4707 return self.tag == IDLInterfaceMember.Tags.MaplikeOrSetlike
4709 def addExtendedAttributes(self, attrs):
4710 for attr in attrs:
4711 self.handleExtendedAttribute(attr)
4712 attrlist = attr.listValue()
4713 self._extendedAttrDict[attr.identifier()] = (
4714 attrlist if len(attrlist) else True
4717 def handleExtendedAttribute(self, attr):
4718 pass
4720 def getExtendedAttribute(self, name):
4721 return self._extendedAttrDict.get(name, None)
4723 def finish(self, scope):
4724 IDLExposureMixins.finish(self, scope)
4726 def validate(self):
4727 if self.isAttr() or self.isMethod():
4728 if self.affects == "Everything" and self.dependsOn != "Everything":
4729 raise WebIDLError(
4730 "Interface member is flagged as affecting "
4731 "everything but not depending on everything. "
4732 "That seems rather unlikely.",
4733 [self.location],
4736 if self.getExtendedAttribute("NewObject"):
4737 if self.dependsOn == "Nothing" or self.dependsOn == "DOMState":
4738 raise WebIDLError(
4739 "A [NewObject] method is not idempotent, "
4740 "so it has to depend on something other than DOM state.",
4741 [self.location],
4743 if self.getExtendedAttribute("Cached") or self.getExtendedAttribute(
4744 "StoreInSlot"
4746 raise WebIDLError(
4747 "A [NewObject] attribute shouldnt be "
4748 "[Cached] or [StoreInSlot], since the point "
4749 "of those is to keep returning the same "
4750 "thing across multiple calls, which is not "
4751 "what [NewObject] does.",
4752 [self.location],
4755 def _setDependsOn(self, dependsOn):
4756 if self.dependsOn != "Everything":
4757 raise WebIDLError(
4758 "Trying to specify multiple different DependsOn, "
4759 "Pure, or Constant extended attributes for "
4760 "attribute",
4761 [self.location],
4763 if dependsOn not in IDLInterfaceMember.DependsOnValues:
4764 raise WebIDLError(
4765 "Invalid [DependsOn=%s] on attribute" % dependsOn, [self.location]
4767 self.dependsOn = dependsOn
4769 def _setAffects(self, affects):
4770 if self.affects != "Everything":
4771 raise WebIDLError(
4772 "Trying to specify multiple different Affects, "
4773 "Pure, or Constant extended attributes for "
4774 "attribute",
4775 [self.location],
4777 if affects not in IDLInterfaceMember.AffectsValues:
4778 raise WebIDLError(
4779 "Invalid [Affects=%s] on attribute" % affects, [self.location]
4781 self.affects = affects
4783 def _addAlias(self, alias):
4784 if alias in self.aliases:
4785 raise WebIDLError(
4786 "Duplicate [Alias=%s] on attribute" % alias, [self.location]
4788 self.aliases.append(alias)
4790 def _addBindingAlias(self, bindingAlias):
4791 if bindingAlias in self.bindingAliases:
4792 raise WebIDLError(
4793 "Duplicate [BindingAlias=%s] on attribute" % bindingAlias,
4794 [self.location],
4796 self.bindingAliases.append(bindingAlias)
4799 class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember):
4800 __slots__ = (
4801 "keyType",
4802 "valueType",
4803 "maplikeOrSetlikeOrIterableType",
4804 "disallowedMemberNames",
4805 "disallowedNonMethodNames",
4808 def __init__(self, location, identifier, ifaceType, keyType, valueType, ifaceKind):
4809 IDLInterfaceMember.__init__(self, location, identifier, ifaceKind)
4810 if keyType is not None:
4811 assert isinstance(keyType, IDLType)
4812 else:
4813 assert valueType is not None
4814 assert ifaceType in ["maplike", "setlike", "iterable", "asynciterable"]
4815 if valueType is not None:
4816 assert isinstance(valueType, IDLType)
4817 self.keyType = keyType
4818 self.valueType = valueType
4819 self.maplikeOrSetlikeOrIterableType = ifaceType
4820 self.disallowedMemberNames = []
4821 self.disallowedNonMethodNames = []
4823 def isMaplike(self):
4824 return self.maplikeOrSetlikeOrIterableType == "maplike"
4826 def isSetlike(self):
4827 return self.maplikeOrSetlikeOrIterableType == "setlike"
4829 def isIterable(self):
4830 return self.maplikeOrSetlikeOrIterableType == "iterable"
4832 def isAsyncIterable(self):
4833 return self.maplikeOrSetlikeOrIterableType == "asynciterable"
4835 def hasKeyType(self):
4836 return self.keyType is not None
4838 def hasValueType(self):
4839 return self.valueType is not None
4841 def checkCollisions(self, members, isAncestor):
4842 for member in members:
4843 # Check that there are no disallowed members
4844 if member.identifier.name in self.disallowedMemberNames and not (
4846 member.isMethod()
4847 and (
4848 member.isStatic() or member.isMaplikeOrSetlikeOrIterableMethod()
4851 or (member.isAttr() and member.isMaplikeOrSetlikeAttr())
4853 raise WebIDLError(
4854 "Member '%s' conflicts "
4855 "with reserved %s name."
4856 % (member.identifier.name, self.maplikeOrSetlikeOrIterableType),
4857 [self.location, member.location],
4859 # Check that there are no disallowed non-method members.
4860 # Ancestor members are always disallowed here; own members
4861 # are disallowed only if they're non-methods.
4862 if (
4863 isAncestor or member.isAttr() or member.isConst()
4864 ) and member.identifier.name in self.disallowedNonMethodNames:
4865 raise WebIDLError(
4866 "Member '%s' conflicts "
4867 "with reserved %s method."
4868 % (member.identifier.name, self.maplikeOrSetlikeOrIterableType),
4869 [self.location, member.location],
4872 def addMethod(
4873 self,
4874 name,
4875 members,
4876 allowExistingOperations,
4877 returnType,
4878 args=[],
4879 chromeOnly=False,
4880 isPure=False,
4881 affectsNothing=False,
4882 newObject=False,
4883 isIteratorAlias=False,
4886 Create an IDLMethod based on the parameters passed in.
4888 - members is the member list to add this function to, since this is
4889 called during the member expansion portion of interface object
4890 building.
4892 - chromeOnly is only True for read-only js implemented classes, to
4893 implement underscore prefixed convenience functions which would
4894 otherwise not be available, unlike the case of C++ bindings.
4896 - isPure is only True for idempotent functions, so it is not valid for
4897 things like keys, values, etc. that return a new object every time.
4899 - affectsNothing means that nothing changes due to this method, which
4900 affects JIT optimization behavior
4902 - newObject means the method creates and returns a new object.
4905 # Only add name to lists for collision checks if it's not chrome
4906 # only.
4907 if chromeOnly:
4908 name = "__" + name
4909 else:
4910 if not allowExistingOperations:
4911 self.disallowedMemberNames.append(name)
4912 else:
4913 self.disallowedNonMethodNames.append(name)
4914 # If allowExistingOperations is True, and another operation exists
4915 # with the same name as the one we're trying to add, don't add the
4916 # maplike/setlike operation.
4917 if allowExistingOperations:
4918 for m in members:
4919 if m.identifier.name == name and m.isMethod() and not m.isStatic():
4920 return
4921 method = IDLMethod(
4922 self.location,
4923 IDLUnresolvedIdentifier(
4924 self.location, name, allowDoubleUnderscore=chromeOnly
4926 returnType,
4927 args,
4928 maplikeOrSetlikeOrIterable=self,
4930 # We need to be able to throw from declaration methods
4931 method.addExtendedAttributes([IDLExtendedAttribute(self.location, ("Throws",))])
4932 if chromeOnly:
4933 method.addExtendedAttributes(
4934 [IDLExtendedAttribute(self.location, ("ChromeOnly",))]
4936 if isPure:
4937 method.addExtendedAttributes(
4938 [IDLExtendedAttribute(self.location, ("Pure",))]
4940 # Following attributes are used for keys/values/entries. Can't mark
4941 # them pure, since they return a new object each time they are run.
4942 if affectsNothing:
4943 method.addExtendedAttributes(
4945 IDLExtendedAttribute(self.location, ("DependsOn", "Everything")),
4946 IDLExtendedAttribute(self.location, ("Affects", "Nothing")),
4949 if newObject:
4950 method.addExtendedAttributes(
4951 [IDLExtendedAttribute(self.location, ("NewObject",))]
4953 if isIteratorAlias:
4954 if not self.isAsyncIterable():
4955 method.addExtendedAttributes(
4956 [IDLExtendedAttribute(self.location, ("Alias", "@@iterator"))]
4958 else:
4959 method.addExtendedAttributes(
4960 [IDLExtendedAttribute(self.location, ("Alias", "@@asyncIterator"))]
4962 members.append(method)
4964 def resolve(self, parentScope):
4965 if self.keyType:
4966 self.keyType.resolveType(parentScope)
4967 if self.valueType:
4968 self.valueType.resolveType(parentScope)
4970 def finish(self, scope):
4971 IDLInterfaceMember.finish(self, scope)
4972 if self.keyType and not self.keyType.isComplete():
4973 t = self.keyType.complete(scope)
4975 assert not isinstance(t, IDLUnresolvedType)
4976 assert not isinstance(t, IDLTypedefType)
4977 assert not isinstance(t.name, IDLUnresolvedIdentifier)
4978 self.keyType = t
4979 if self.valueType and not self.valueType.isComplete():
4980 t = self.valueType.complete(scope)
4982 assert not isinstance(t, IDLUnresolvedType)
4983 assert not isinstance(t, IDLTypedefType)
4984 assert not isinstance(t.name, IDLUnresolvedIdentifier)
4985 self.valueType = t
4987 def validate(self):
4988 IDLInterfaceMember.validate(self)
4990 def handleExtendedAttribute(self, attr):
4991 IDLInterfaceMember.handleExtendedAttribute(self, attr)
4993 def _getDependentObjects(self):
4994 deps = set()
4995 if self.keyType:
4996 deps.add(self.keyType)
4997 if self.valueType:
4998 deps.add(self.valueType)
4999 return deps
5001 def getForEachArguments(self):
5002 return [
5003 IDLArgument(
5004 self.location,
5005 IDLUnresolvedIdentifier(
5006 BuiltinLocation("<auto-generated-identifier>"), "callback"
5008 BuiltinTypes[IDLBuiltinType.Types.object],
5010 IDLArgument(
5011 self.location,
5012 IDLUnresolvedIdentifier(
5013 BuiltinLocation("<auto-generated-identifier>"), "thisArg"
5015 BuiltinTypes[IDLBuiltinType.Types.any],
5016 optional=True,
5021 # Iterable adds ES6 iterator style functions and traits
5022 # (keys/values/entries/@@iterator) to an interface.
5023 class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase):
5024 __slots__ = ("iteratorType",)
5026 def __init__(self, location, identifier, keyType, valueType, scope):
5027 IDLMaplikeOrSetlikeOrIterableBase.__init__(
5028 self,
5029 location,
5030 identifier,
5031 "iterable",
5032 keyType,
5033 valueType,
5034 IDLInterfaceMember.Tags.Iterable,
5036 self.iteratorType = None
5038 def __str__(self):
5039 return "declared iterable with key '%s' and value '%s'" % (
5040 self.keyType,
5041 self.valueType,
5044 def expand(self, members):
5046 In order to take advantage of all of the method machinery in Codegen,
5047 we generate our functions as if they were part of the interface
5048 specification during parsing.
5050 # We only need to add entries/keys/values here if we're a pair iterator.
5051 # Value iterators just copy these from %ArrayPrototype% instead.
5052 if not self.isPairIterator():
5053 return
5055 # object entries()
5056 self.addMethod(
5057 "entries",
5058 members,
5059 False,
5060 self.iteratorType,
5061 affectsNothing=True,
5062 newObject=True,
5063 isIteratorAlias=True,
5065 # object keys()
5066 self.addMethod(
5067 "keys",
5068 members,
5069 False,
5070 self.iteratorType,
5071 affectsNothing=True,
5072 newObject=True,
5074 # object values()
5075 self.addMethod(
5076 "values",
5077 members,
5078 False,
5079 self.iteratorType,
5080 affectsNothing=True,
5081 newObject=True,
5084 # undefined forEach(callback(valueType, keyType), optional any thisArg)
5085 self.addMethod(
5086 "forEach",
5087 members,
5088 False,
5089 BuiltinTypes[IDLBuiltinType.Types.undefined],
5090 self.getForEachArguments(),
5093 def isValueIterator(self):
5094 return not self.isPairIterator()
5096 def isPairIterator(self):
5097 return self.hasKeyType()
5100 class IDLAsyncIterable(IDLMaplikeOrSetlikeOrIterableBase):
5101 __slots__ = "iteratorType", "argList"
5103 def __init__(self, location, identifier, keyType, valueType, argList, scope):
5104 for arg in argList:
5105 if not arg.optional:
5106 raise WebIDLError(
5107 "The arguments of the asynchronously iterable declaration on "
5108 "%s must all be optional arguments." % identifier,
5109 [arg.location],
5112 IDLMaplikeOrSetlikeOrIterableBase.__init__(
5113 self,
5114 location,
5115 identifier,
5116 "asynciterable",
5117 keyType,
5118 valueType,
5119 IDLInterfaceMember.Tags.AsyncIterable,
5121 self.iteratorType = None
5122 self.argList = argList
5124 def __str__(self):
5125 return "declared async iterable with key '%s' and value '%s'" % (
5126 self.keyType,
5127 self.valueType,
5130 def expand(self, members):
5132 In order to take advantage of all of the method machinery in Codegen,
5133 we generate our functions as if they were part of the interface
5134 specification during parsing.
5136 # object values()
5137 self.addMethod(
5138 "values",
5139 members,
5140 False,
5141 self.iteratorType,
5142 self.argList,
5143 affectsNothing=True,
5144 newObject=True,
5145 isIteratorAlias=(not self.isPairIterator()),
5148 # We only need to add entries/keys here if we're a pair iterator.
5149 if not self.isPairIterator():
5150 return
5152 # Methods can't share their IDLArguments, so we need to make copies here.
5153 def copyArgList(argList):
5154 return map(copy.copy, argList)
5156 # object entries()
5157 self.addMethod(
5158 "entries",
5159 members,
5160 False,
5161 self.iteratorType,
5162 copyArgList(self.argList),
5163 affectsNothing=True,
5164 newObject=True,
5165 isIteratorAlias=True,
5167 # object keys()
5168 self.addMethod(
5169 "keys",
5170 members,
5171 False,
5172 self.iteratorType,
5173 copyArgList(self.argList),
5174 affectsNothing=True,
5175 newObject=True,
5178 def isValueIterator(self):
5179 return not self.isPairIterator()
5181 def isPairIterator(self):
5182 return self.hasKeyType()
5185 # MaplikeOrSetlike adds ES6 map-or-set-like traits to an interface.
5186 class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase):
5187 __slots__ = "readonly", "slotIndices", "prefix"
5189 def __init__(
5190 self, location, identifier, maplikeOrSetlikeType, readonly, keyType, valueType
5192 IDLMaplikeOrSetlikeOrIterableBase.__init__(
5193 self,
5194 location,
5195 identifier,
5196 maplikeOrSetlikeType,
5197 keyType,
5198 valueType,
5199 IDLInterfaceMember.Tags.MaplikeOrSetlike,
5201 self.readonly = readonly
5202 self.slotIndices = None
5204 # When generating JSAPI access code, we need to know the backing object
5205 # type prefix to create the correct function. Generate here for reuse.
5206 if self.isMaplike():
5207 self.prefix = "Map"
5208 elif self.isSetlike():
5209 self.prefix = "Set"
5211 def __str__(self):
5212 return "declared '%s' with key '%s'" % (
5213 self.maplikeOrSetlikeOrIterableType,
5214 self.keyType,
5217 def expand(self, members):
5219 In order to take advantage of all of the method machinery in Codegen,
5220 we generate our functions as if they were part of the interface
5221 specification during parsing.
5223 # Both maplike and setlike have a size attribute
5224 members.append(
5225 IDLAttribute(
5226 self.location,
5227 IDLUnresolvedIdentifier(
5228 BuiltinLocation("<auto-generated-identifier>"), "size"
5230 BuiltinTypes[IDLBuiltinType.Types.unsigned_long],
5231 True,
5232 maplikeOrSetlike=self,
5235 self.reserved_ro_names = ["size"]
5236 self.disallowedMemberNames.append("size")
5238 # object entries()
5239 self.addMethod(
5240 "entries",
5241 members,
5242 False,
5243 BuiltinTypes[IDLBuiltinType.Types.object],
5244 affectsNothing=True,
5245 isIteratorAlias=self.isMaplike(),
5247 # object keys()
5248 self.addMethod(
5249 "keys",
5250 members,
5251 False,
5252 BuiltinTypes[IDLBuiltinType.Types.object],
5253 affectsNothing=True,
5255 # object values()
5256 self.addMethod(
5257 "values",
5258 members,
5259 False,
5260 BuiltinTypes[IDLBuiltinType.Types.object],
5261 affectsNothing=True,
5262 isIteratorAlias=self.isSetlike(),
5265 # undefined forEach(callback(valueType, keyType), thisVal)
5266 self.addMethod(
5267 "forEach",
5268 members,
5269 False,
5270 BuiltinTypes[IDLBuiltinType.Types.undefined],
5271 self.getForEachArguments(),
5274 def getKeyArg():
5275 return IDLArgument(
5276 self.location,
5277 IDLUnresolvedIdentifier(self.location, "key"),
5278 self.keyType,
5281 # boolean has(keyType key)
5282 self.addMethod(
5283 "has",
5284 members,
5285 False,
5286 BuiltinTypes[IDLBuiltinType.Types.boolean],
5287 [getKeyArg()],
5288 isPure=True,
5291 if not self.readonly:
5292 # undefined clear()
5293 self.addMethod(
5294 "clear", members, True, BuiltinTypes[IDLBuiltinType.Types.undefined], []
5296 # boolean delete(keyType key)
5297 self.addMethod(
5298 "delete",
5299 members,
5300 True,
5301 BuiltinTypes[IDLBuiltinType.Types.boolean],
5302 [getKeyArg()],
5305 if self.isSetlike():
5306 if not self.readonly:
5307 # Add returns the set object it just added to.
5308 # object add(keyType key)
5310 self.addMethod(
5311 "add",
5312 members,
5313 True,
5314 BuiltinTypes[IDLBuiltinType.Types.object],
5315 [getKeyArg()],
5317 return
5319 # If we get this far, we're a maplike declaration.
5321 # valueType get(keyType key)
5323 # Note that instead of the value type, we're using any here. The
5324 # validity checks should happen as things are inserted into the map,
5325 # and using any as the return type makes code generation much simpler.
5327 # TODO: Bug 1155340 may change this to use specific type to provide
5328 # more info to JIT.
5329 self.addMethod(
5330 "get",
5331 members,
5332 False,
5333 BuiltinTypes[IDLBuiltinType.Types.any],
5334 [getKeyArg()],
5335 isPure=True,
5338 def getValueArg():
5339 return IDLArgument(
5340 self.location,
5341 IDLUnresolvedIdentifier(self.location, "value"),
5342 self.valueType,
5345 if not self.readonly:
5346 self.addMethod(
5347 "set",
5348 members,
5349 True,
5350 BuiltinTypes[IDLBuiltinType.Types.object],
5351 [getKeyArg(), getValueArg()],
5355 class IDLConst(IDLInterfaceMember):
5356 __slots__ = "type", "value"
5358 def __init__(self, location, identifier, type, value):
5359 IDLInterfaceMember.__init__(
5360 self, location, identifier, IDLInterfaceMember.Tags.Const
5363 assert isinstance(type, IDLType)
5364 if type.isDictionary():
5365 raise WebIDLError(
5366 "A constant cannot be of a dictionary type", [self.location]
5368 if type.isRecord():
5369 raise WebIDLError("A constant cannot be of a record type", [self.location])
5370 self.type = type
5371 self.value = value
5373 if identifier.name == "prototype":
5374 raise WebIDLError(
5375 "The identifier of a constant must not be 'prototype'", [location]
5378 def __str__(self):
5379 return "'%s' const '%s'" % (self.type, self.identifier)
5381 def finish(self, scope):
5382 IDLInterfaceMember.finish(self, scope)
5384 if not self.type.isComplete():
5385 type = self.type.complete(scope)
5386 if not type.isPrimitive() and not type.isString():
5387 locations = [self.type.location, type.location]
5388 try:
5389 locations.append(type.inner.location)
5390 except Exception:
5391 pass
5392 raise WebIDLError("Incorrect type for constant", locations)
5393 self.type = type
5395 # The value might not match the type
5396 coercedValue = self.value.coerceToType(self.type, self.location)
5397 assert coercedValue
5399 self.value = coercedValue
5401 def validate(self):
5402 IDLInterfaceMember.validate(self)
5404 def handleExtendedAttribute(self, attr):
5405 identifier = attr.identifier()
5406 if identifier == "Exposed":
5407 convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
5408 elif (
5409 identifier == "Pref"
5410 or identifier == "ChromeOnly"
5411 or identifier == "Func"
5412 or identifier == "Trial"
5413 or identifier == "SecureContext"
5414 or identifier == "NonEnumerable"
5416 # Known attributes that we don't need to do anything with here
5417 pass
5418 else:
5419 raise WebIDLError(
5420 "Unknown extended attribute %s on constant" % identifier,
5421 [attr.location],
5423 IDLInterfaceMember.handleExtendedAttribute(self, attr)
5425 def _getDependentObjects(self):
5426 return set([self.type, self.value])
5429 class IDLAttribute(IDLInterfaceMember):
5430 __slots__ = (
5431 "type",
5432 "readonly",
5433 "inherit",
5434 "_static",
5435 "legacyLenientThis",
5436 "_legacyUnforgeable",
5437 "stringifier",
5438 "slotIndices",
5439 "maplikeOrSetlike",
5440 "dependsOn",
5441 "affects",
5442 "bindingAliases",
5445 def __init__(
5446 self,
5447 location,
5448 identifier,
5449 type,
5450 readonly,
5451 inherit=False,
5452 static=False,
5453 stringifier=False,
5454 maplikeOrSetlike=None,
5455 extendedAttrDict=None,
5457 IDLInterfaceMember.__init__(
5458 self,
5459 location,
5460 identifier,
5461 IDLInterfaceMember.Tags.Attr,
5462 extendedAttrDict=extendedAttrDict,
5465 assert isinstance(type, IDLType)
5466 self.type = type
5467 self.readonly = readonly
5468 self.inherit = inherit
5469 self._static = static
5470 self.legacyLenientThis = False
5471 self._legacyUnforgeable = False
5472 self.stringifier = stringifier
5473 # slotIndices can be a dictionary mapping concrete interface name to
5474 # either a slot index in the binding object, or to a tuple of the slot
5475 # index in the binding object and an index in the array that's stored
5476 # in that slot.
5477 self.slotIndices = None
5478 assert maplikeOrSetlike is None or isinstance(
5479 maplikeOrSetlike, IDLMaplikeOrSetlike
5481 self.maplikeOrSetlike = maplikeOrSetlike
5482 self.dependsOn = "Everything"
5483 self.affects = "Everything"
5484 self.bindingAliases = []
5486 if static and identifier.name == "prototype":
5487 raise WebIDLError(
5488 "The identifier of a static attribute must not be 'prototype'",
5489 [location],
5492 if readonly and inherit:
5493 raise WebIDLError(
5494 "An attribute cannot be both 'readonly' and 'inherit'", [self.location]
5497 def isStatic(self):
5498 return self._static
5500 def forceStatic(self):
5501 self._static = True
5503 def __str__(self):
5504 return "'%s' attribute '%s'" % (self.type, self.identifier)
5506 def finish(self, scope):
5507 IDLInterfaceMember.finish(self, scope)
5509 if not self.type.isComplete():
5510 t = self.type.complete(scope)
5512 assert not isinstance(t, IDLUnresolvedType)
5513 assert not isinstance(t, IDLTypedefType)
5514 assert not isinstance(t.name, IDLUnresolvedIdentifier)
5515 self.type = t
5517 if self.readonly and (
5518 self.type.hasClamp()
5519 or self.type.hasEnforceRange()
5520 or self.type.hasAllowShared()
5521 or self.type.legacyNullToEmptyString
5523 raise WebIDLError(
5524 "A readonly attribute cannot be [Clamp] or [EnforceRange] or [AllowShared]",
5525 [self.location],
5527 if self.type.isDictionary() and not self.getExtendedAttribute("Cached"):
5528 raise WebIDLError(
5529 "An attribute cannot be of a dictionary type", [self.location]
5531 if self.type.isSequence() and not (
5532 self.getExtendedAttribute("Cached")
5533 or self.getExtendedAttribute("ReflectedHTMLAttributeReturningFrozenArray")
5535 raise WebIDLError(
5536 "A non-cached attribute cannot be of a sequence type",
5537 [self.location],
5539 if self.type.isRecord() and not self.getExtendedAttribute("Cached"):
5540 raise WebIDLError(
5541 "A non-cached attribute cannot be of a record type", [self.location]
5543 if self.type.isUnion():
5544 for f in self.type.unroll().flatMemberTypes:
5545 if f.isDictionary():
5546 raise WebIDLError(
5547 "An attribute cannot be of a union "
5548 "type if one of its member types (or "
5549 "one of its member types's member "
5550 "types, and so on) is a dictionary "
5551 "type",
5552 [self.location, f.location],
5554 if f.isSequence():
5555 raise WebIDLError(
5556 "An attribute cannot be of a union "
5557 "type if one of its member types (or "
5558 "one of its member types's member "
5559 "types, and so on) is a sequence "
5560 "type",
5561 [self.location, f.location],
5563 if f.isRecord():
5564 raise WebIDLError(
5565 "An attribute cannot be of a union "
5566 "type if one of its member types (or "
5567 "one of its member types's member "
5568 "types, and so on) is a record "
5569 "type",
5570 [self.location, f.location],
5572 if not self.type.isInterface() and self.getExtendedAttribute("PutForwards"):
5573 raise WebIDLError(
5574 "An attribute with [PutForwards] must have an "
5575 "interface type as its type",
5576 [self.location],
5579 if not self.type.isInterface() and self.getExtendedAttribute("SameObject"):
5580 raise WebIDLError(
5581 "An attribute with [SameObject] must have an "
5582 "interface type as its type",
5583 [self.location],
5586 if self.type.isPromise() and not self.readonly:
5587 raise WebIDLError(
5588 "Promise-returning attributes must be readonly", [self.location]
5591 if self.type.isObservableArray():
5592 if self.isStatic():
5593 raise WebIDLError(
5594 "A static attribute cannot have an ObservableArray type",
5595 [self.location],
5597 if self.getExtendedAttribute("Cached") or self.getExtendedAttribute(
5598 "StoreInSlot"
5600 raise WebIDLError(
5601 "[Cached] and [StoreInSlot] must not be used "
5602 "on an attribute whose type is ObservableArray",
5603 [self.location],
5606 def validate(self):
5607 def typeContainsChromeOnlyDictionaryMember(type):
5608 if type.nullable() or type.isSequence() or type.isRecord():
5609 return typeContainsChromeOnlyDictionaryMember(type.inner)
5611 if type.isUnion():
5612 for memberType in type.flatMemberTypes:
5613 (contains, location) = typeContainsChromeOnlyDictionaryMember(
5614 memberType
5616 if contains:
5617 return (True, location)
5619 if type.isDictionary():
5620 dictionary = type.inner
5621 while dictionary:
5622 (contains, location) = dictionaryContainsChromeOnlyMember(
5623 dictionary
5625 if contains:
5626 return (True, location)
5627 dictionary = dictionary.parent
5629 return (False, None)
5631 def dictionaryContainsChromeOnlyMember(dictionary):
5632 for member in dictionary.members:
5633 if member.getExtendedAttribute("ChromeOnly"):
5634 return (True, member.location)
5635 (contains, location) = typeContainsChromeOnlyDictionaryMember(
5636 member.type
5638 if contains:
5639 return (True, location)
5640 return (False, None)
5642 IDLInterfaceMember.validate(self)
5644 if self.getExtendedAttribute("Cached") or self.getExtendedAttribute(
5645 "StoreInSlot"
5647 if not self.affects == "Nothing":
5648 raise WebIDLError(
5649 "Cached attributes and attributes stored in "
5650 "slots must be Constant or Pure or "
5651 "Affects=Nothing, since the getter won't always "
5652 "be called.",
5653 [self.location],
5655 (contains, location) = typeContainsChromeOnlyDictionaryMember(self.type)
5656 if contains:
5657 raise WebIDLError(
5658 "[Cached] and [StoreInSlot] must not be used "
5659 "on an attribute whose type contains a "
5660 "[ChromeOnly] dictionary member",
5661 [self.location, location],
5663 if self.getExtendedAttribute("Frozen"):
5664 if (
5665 not self.type.isSequence()
5666 and not self.type.isDictionary()
5667 and not self.type.isRecord()
5669 raise WebIDLError(
5670 "[Frozen] is only allowed on "
5671 "sequence-valued, dictionary-valued, and "
5672 "record-valued attributes",
5673 [self.location],
5675 if self.getExtendedAttribute("ReflectedHTMLAttributeReturningFrozenArray"):
5676 if self.getExtendedAttribute("Cached") or self.getExtendedAttribute(
5677 "StoreInSlot"
5679 raise WebIDLError(
5680 "[ReflectedHTMLAttributeReturningFrozenArray] can't be combined "
5681 "with [Cached] or [StoreInSlot]",
5682 [self.location],
5684 if not self.type.isSequence():
5685 raise WebIDLError(
5686 "[ReflectedHTMLAttributeReturningFrozenArray] is only allowed on "
5687 "sequence-valued attributes",
5688 [self.location],
5691 def interfaceTypeIsOrInheritsFromElement(type):
5692 return type.identifier.name == "Element" or (
5693 type.parent is not None
5694 and interfaceTypeIsOrInheritsFromElement(type.parent)
5697 sequenceMemberType = self.type.unroll()
5698 if (
5699 not sequenceMemberType.isInterface()
5700 or not interfaceTypeIsOrInheritsFromElement(sequenceMemberType.inner)
5702 raise WebIDLError(
5703 "[ReflectedHTMLAttributeReturningFrozenArray] is only allowed on "
5704 "sequence-valued attributes containing interface values of type "
5705 "Element or an interface inheriting from Element",
5706 [self.location],
5708 if not self.type.unroll().isExposedInAllOf(self.exposureSet):
5709 raise WebIDLError(
5710 "Attribute returns a type that is not exposed "
5711 "everywhere where the attribute is exposed",
5712 [self.location],
5714 if self.getExtendedAttribute("CEReactions"):
5715 if self.readonly:
5716 raise WebIDLError(
5717 "[CEReactions] is not allowed on readonly attributes",
5718 [self.location],
5721 def handleExtendedAttribute(self, attr):
5722 identifier = attr.identifier()
5723 if (
5724 identifier == "SetterThrows"
5725 or identifier == "SetterCanOOM"
5726 or identifier == "SetterNeedsSubjectPrincipal"
5727 ) and self.readonly:
5728 raise WebIDLError(
5729 "Readonly attributes must not be flagged as [%s]" % identifier,
5730 [self.location],
5732 elif identifier == "BindingAlias":
5733 if not attr.hasValue():
5734 raise WebIDLError(
5735 "[BindingAlias] takes an identifier or string", [attr.location]
5737 self._addBindingAlias(attr.value())
5738 elif (
5740 identifier == "Throws"
5741 or identifier == "GetterThrows"
5742 or identifier == "CanOOM"
5743 or identifier == "GetterCanOOM"
5745 and self.getExtendedAttribute("StoreInSlot")
5746 ) or (
5747 identifier == "StoreInSlot"
5748 and (
5749 self.getExtendedAttribute("Throws")
5750 or self.getExtendedAttribute("GetterThrows")
5751 or self.getExtendedAttribute("CanOOM")
5752 or self.getExtendedAttribute("GetterCanOOM")
5755 raise WebIDLError("Throwing things can't be [StoreInSlot]", [attr.location])
5756 elif identifier == "LegacyLenientThis":
5757 if not attr.noArguments():
5758 raise WebIDLError(
5759 "[LegacyLenientThis] must take no arguments", [attr.location]
5761 if self.isStatic():
5762 raise WebIDLError(
5763 "[LegacyLenientThis] is only allowed on non-static attributes",
5764 [attr.location, self.location],
5766 if self.getExtendedAttribute("CrossOriginReadable"):
5767 raise WebIDLError(
5768 "[LegacyLenientThis] is not allowed in combination "
5769 "with [CrossOriginReadable]",
5770 [attr.location, self.location],
5772 if self.getExtendedAttribute("CrossOriginWritable"):
5773 raise WebIDLError(
5774 "[LegacyLenientThis] is not allowed in combination "
5775 "with [CrossOriginWritable]",
5776 [attr.location, self.location],
5778 self.legacyLenientThis = True
5779 elif identifier == "LegacyUnforgeable":
5780 if self.isStatic():
5781 raise WebIDLError(
5782 "[LegacyUnforgeable] is only allowed on non-static attributes",
5783 [attr.location, self.location],
5785 self._legacyUnforgeable = True
5786 elif identifier == "SameObject" and not self.readonly:
5787 raise WebIDLError(
5788 "[SameObject] only allowed on readonly attributes",
5789 [attr.location, self.location],
5791 elif identifier == "Constant" and not self.readonly:
5792 raise WebIDLError(
5793 "[Constant] only allowed on readonly attributes",
5794 [attr.location, self.location],
5796 elif identifier == "PutForwards":
5797 if not self.readonly:
5798 raise WebIDLError(
5799 "[PutForwards] is only allowed on readonly attributes",
5800 [attr.location, self.location],
5802 if self.type.isPromise():
5803 raise WebIDLError(
5804 "[PutForwards] is not allowed on Promise-typed attributes",
5805 [attr.location, self.location],
5807 if self.isStatic():
5808 raise WebIDLError(
5809 "[PutForwards] is only allowed on non-static attributes",
5810 [attr.location, self.location],
5812 if self.getExtendedAttribute("Replaceable") is not None:
5813 raise WebIDLError(
5814 "[PutForwards] and [Replaceable] can't both "
5815 "appear on the same attribute",
5816 [attr.location, self.location],
5818 if not attr.hasValue():
5819 raise WebIDLError(
5820 "[PutForwards] takes an identifier", [attr.location, self.location]
5822 elif identifier == "Replaceable":
5823 if not attr.noArguments():
5824 raise WebIDLError(
5825 "[Replaceable] must take no arguments", [attr.location]
5827 if not self.readonly:
5828 raise WebIDLError(
5829 "[Replaceable] is only allowed on readonly attributes",
5830 [attr.location, self.location],
5832 if self.type.isPromise():
5833 raise WebIDLError(
5834 "[Replaceable] is not allowed on Promise-typed attributes",
5835 [attr.location, self.location],
5837 if self.isStatic():
5838 raise WebIDLError(
5839 "[Replaceable] is only allowed on non-static attributes",
5840 [attr.location, self.location],
5842 if self.getExtendedAttribute("PutForwards") is not None:
5843 raise WebIDLError(
5844 "[PutForwards] and [Replaceable] can't both "
5845 "appear on the same attribute",
5846 [attr.location, self.location],
5848 elif identifier == "LegacyLenientSetter":
5849 if not attr.noArguments():
5850 raise WebIDLError(
5851 "[LegacyLenientSetter] must take no arguments", [attr.location]
5853 if not self.readonly:
5854 raise WebIDLError(
5855 "[LegacyLenientSetter] is only allowed on readonly attributes",
5856 [attr.location, self.location],
5858 if self.type.isPromise():
5859 raise WebIDLError(
5860 "[LegacyLenientSetter] is not allowed on "
5861 "Promise-typed attributes",
5862 [attr.location, self.location],
5864 if self.isStatic():
5865 raise WebIDLError(
5866 "[LegacyLenientSetter] is only allowed on non-static attributes",
5867 [attr.location, self.location],
5869 if self.getExtendedAttribute("PutForwards") is not None:
5870 raise WebIDLError(
5871 "[LegacyLenientSetter] and [PutForwards] can't both "
5872 "appear on the same attribute",
5873 [attr.location, self.location],
5875 if self.getExtendedAttribute("Replaceable") is not None:
5876 raise WebIDLError(
5877 "[LegacyLenientSetter] and [Replaceable] can't both "
5878 "appear on the same attribute",
5879 [attr.location, self.location],
5881 elif identifier == "LenientFloat":
5882 if self.readonly:
5883 raise WebIDLError(
5884 "[LenientFloat] used on a readonly attribute",
5885 [attr.location, self.location],
5887 if not self.type.includesRestrictedFloat():
5888 raise WebIDLError(
5889 "[LenientFloat] used on an attribute with a "
5890 "non-restricted-float type",
5891 [attr.location, self.location],
5893 elif identifier == "StoreInSlot":
5894 if self.getExtendedAttribute("Cached"):
5895 raise WebIDLError(
5896 "[StoreInSlot] and [Cached] must not be "
5897 "specified on the same attribute",
5898 [attr.location, self.location],
5900 elif identifier == "Cached":
5901 if self.getExtendedAttribute("StoreInSlot"):
5902 raise WebIDLError(
5903 "[Cached] and [StoreInSlot] must not be "
5904 "specified on the same attribute",
5905 [attr.location, self.location],
5907 elif identifier == "CrossOriginReadable" or identifier == "CrossOriginWritable":
5908 if not attr.noArguments():
5909 raise WebIDLError(
5910 "[%s] must take no arguments" % identifier, [attr.location]
5912 if self.isStatic():
5913 raise WebIDLError(
5914 "[%s] is only allowed on non-static attributes" % identifier,
5915 [attr.location, self.location],
5917 if self.getExtendedAttribute("LegacyLenientThis"):
5918 raise WebIDLError(
5919 "[LegacyLenientThis] is not allowed in combination "
5920 "with [%s]" % identifier,
5921 [attr.location, self.location],
5923 elif identifier == "Exposed":
5924 convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
5925 elif identifier == "Pure":
5926 if not attr.noArguments():
5927 raise WebIDLError("[Pure] must take no arguments", [attr.location])
5928 self._setDependsOn("DOMState")
5929 self._setAffects("Nothing")
5930 elif identifier == "Constant" or identifier == "SameObject":
5931 if not attr.noArguments():
5932 raise WebIDLError(
5933 "[%s] must take no arguments" % identifier, [attr.location]
5935 self._setDependsOn("Nothing")
5936 self._setAffects("Nothing")
5937 elif identifier == "Affects":
5938 if not attr.hasValue():
5939 raise WebIDLError("[Affects] takes an identifier", [attr.location])
5940 self._setAffects(attr.value())
5941 elif identifier == "DependsOn":
5942 if not attr.hasValue():
5943 raise WebIDLError("[DependsOn] takes an identifier", [attr.location])
5944 if (
5945 attr.value() != "Everything"
5946 and attr.value() != "DOMState"
5947 and not self.readonly
5949 raise WebIDLError(
5950 "[DependsOn=%s] only allowed on "
5951 "readonly attributes" % attr.value(),
5952 [attr.location, self.location],
5954 self._setDependsOn(attr.value())
5955 elif identifier == "UseCounter":
5956 if self.stringifier:
5957 raise WebIDLError(
5958 "[UseCounter] must not be used on a stringifier attribute",
5959 [attr.location, self.location],
5961 elif identifier == "Unscopable":
5962 if not attr.noArguments():
5963 raise WebIDLError(
5964 "[Unscopable] must take no arguments", [attr.location]
5966 if self.isStatic():
5967 raise WebIDLError(
5968 "[Unscopable] is only allowed on non-static "
5969 "attributes and operations",
5970 [attr.location, self.location],
5972 elif identifier == "CEReactions":
5973 if not attr.noArguments():
5974 raise WebIDLError(
5975 "[CEReactions] must take no arguments", [attr.location]
5977 elif (
5978 identifier == "Pref"
5979 or identifier == "Deprecated"
5980 or identifier == "SetterThrows"
5981 or identifier == "Throws"
5982 or identifier == "GetterThrows"
5983 or identifier == "SetterCanOOM"
5984 or identifier == "CanOOM"
5985 or identifier == "GetterCanOOM"
5986 or identifier == "ChromeOnly"
5987 or identifier == "Func"
5988 or identifier == "Trial"
5989 or identifier == "SecureContext"
5990 or identifier == "Frozen"
5991 or identifier == "NewObject"
5992 or identifier == "NeedsSubjectPrincipal"
5993 or identifier == "SetterNeedsSubjectPrincipal"
5994 or identifier == "GetterNeedsSubjectPrincipal"
5995 or identifier == "NeedsCallerType"
5996 or identifier == "BinaryName"
5997 or identifier == "NonEnumerable"
5998 or identifier == "BindingTemplate"
5999 or identifier == "ReflectedHTMLAttributeReturningFrozenArray"
6001 # Known attributes that we don't need to do anything with here
6002 pass
6003 else:
6004 raise WebIDLError(
6005 "Unknown extended attribute %s on attribute" % identifier,
6006 [attr.location],
6008 IDLInterfaceMember.handleExtendedAttribute(self, attr)
6010 def getExtendedAttributes(self):
6011 return self._extendedAttrDict
6013 def resolve(self, parentScope):
6014 assert isinstance(parentScope, IDLScope)
6015 self.type.resolveType(parentScope)
6016 IDLObjectWithIdentifier.resolve(self, parentScope)
6018 def hasLegacyLenientThis(self):
6019 return self.legacyLenientThis
6021 def isMaplikeOrSetlikeAttr(self):
6023 True if this attribute was generated from an interface with
6024 maplike/setlike (e.g. this is the size attribute for
6025 maplike/setlike)
6027 return self.maplikeOrSetlike is not None
6029 def isLegacyUnforgeable(self):
6030 return self._legacyUnforgeable
6032 def _getDependentObjects(self):
6033 return set([self.type])
6035 def expand(self, members):
6036 assert self.stringifier
6037 if (
6038 not self.type.isDOMString()
6039 and not self.type.isUSVString()
6040 and not self.type.isUTF8String()
6042 raise WebIDLError(
6043 "The type of a stringifer attribute must be "
6044 "either DOMString, USVString or UTF8String",
6045 [self.location],
6047 identifier = IDLUnresolvedIdentifier(
6048 self.location, "__stringifier", allowDoubleUnderscore=True
6050 method = IDLMethod(
6051 self.location,
6052 identifier,
6053 returnType=self.type,
6054 arguments=[],
6055 stringifier=True,
6056 underlyingAttr=self,
6058 allowedExtAttrs = ["Throws", "NeedsSubjectPrincipal", "Pure"]
6059 # Safe to ignore these as they are only meaningful for attributes
6060 attributeOnlyExtAttrs = [
6061 "CEReactions",
6062 "CrossOriginWritable",
6063 "SetterThrows",
6065 for key, value in self._extendedAttrDict.items():
6066 if key in allowedExtAttrs:
6067 if value is not True:
6068 raise WebIDLError(
6069 "[%s] with a value is currently "
6070 "unsupported in stringifier attributes, "
6071 "please file a bug to add support" % key,
6072 [self.location],
6074 method.addExtendedAttributes(
6075 [IDLExtendedAttribute(self.location, (key,))]
6077 elif key not in attributeOnlyExtAttrs:
6078 raise WebIDLError(
6079 "[%s] is currently unsupported in "
6080 "stringifier attributes, please file a bug "
6081 "to add support" % key,
6082 [self.location],
6084 members.append(method)
6087 class IDLArgument(IDLObjectWithIdentifier):
6088 __slots__ = (
6089 "type",
6090 "optional",
6091 "defaultValue",
6092 "variadic",
6093 "dictionaryMember",
6094 "_isComplete",
6095 "_allowTreatNonCallableAsNull",
6096 "_extendedAttrDict",
6097 "allowTypeAttributes",
6100 def __init__(
6101 self,
6102 location,
6103 identifier,
6104 type,
6105 optional=False,
6106 defaultValue=None,
6107 variadic=False,
6108 dictionaryMember=False,
6109 allowTypeAttributes=False,
6111 IDLObjectWithIdentifier.__init__(self, location, None, identifier)
6113 assert isinstance(type, IDLType)
6114 self.type = type
6116 self.optional = optional
6117 self.defaultValue = defaultValue
6118 self.variadic = variadic
6119 self.dictionaryMember = dictionaryMember
6120 self._isComplete = False
6121 self._allowTreatNonCallableAsNull = False
6122 self._extendedAttrDict = {}
6123 self.allowTypeAttributes = allowTypeAttributes
6125 assert not variadic or optional
6126 assert not variadic or not defaultValue
6128 def addExtendedAttributes(self, attrs):
6129 for attribute in attrs:
6130 identifier = attribute.identifier()
6131 if self.allowTypeAttributes and (
6132 identifier == "EnforceRange"
6133 or identifier == "Clamp"
6134 or identifier == "LegacyNullToEmptyString"
6135 or identifier == "AllowShared"
6137 self.type = self.type.withExtendedAttributes([attribute])
6138 elif identifier == "TreatNonCallableAsNull":
6139 self._allowTreatNonCallableAsNull = True
6140 elif self.dictionaryMember and (
6141 identifier == "ChromeOnly"
6142 or identifier == "Func"
6143 or identifier == "Trial"
6144 or identifier == "Pref"
6146 if not self.optional:
6147 raise WebIDLError(
6148 "[%s] must not be used on a required "
6149 "dictionary member" % identifier,
6150 [attribute.location],
6152 elif self.dictionaryMember and identifier == "BinaryType":
6153 if not len(attribute.listValue()) == 1:
6154 raise WebIDLError(
6155 "[%s] BinaryType must take one argument" % identifier,
6156 [attribute.location],
6158 if not self.defaultValue:
6159 raise WebIDLError(
6160 "[%s] BinaryType can't be used without default value"
6161 % identifier,
6162 [attribute.location],
6164 else:
6165 raise WebIDLError(
6166 "Unhandled extended attribute on %s"
6168 "a dictionary member"
6169 if self.dictionaryMember
6170 else "an argument"
6172 [attribute.location],
6174 attrlist = attribute.listValue()
6175 self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
6177 def getExtendedAttribute(self, name):
6178 return self._extendedAttrDict.get(name, None)
6180 def isComplete(self):
6181 return self._isComplete
6183 def complete(self, scope):
6184 if self._isComplete:
6185 return
6187 self._isComplete = True
6189 if not self.type.isComplete():
6190 type = self.type.complete(scope)
6191 assert not isinstance(type, IDLUnresolvedType)
6192 assert not isinstance(type, IDLTypedefType)
6193 assert not isinstance(type.name, IDLUnresolvedIdentifier)
6194 self.type = type
6196 if self.type.isUndefined():
6197 raise WebIDLError(
6198 "undefined must not be used as the type of an argument in any circumstance",
6199 [self.location],
6202 if self.type.isAny():
6203 assert self.defaultValue is None or isinstance(
6204 self.defaultValue, IDLNullValue
6206 # optional 'any' values always have a default value
6207 if self.optional and not self.defaultValue and not self.variadic:
6208 # Set the default value to undefined, for simplicity, so the
6209 # codegen doesn't have to special-case this.
6210 self.defaultValue = IDLUndefinedValue(self.location)
6212 if self.dictionaryMember and self.type.legacyNullToEmptyString:
6213 raise WebIDLError(
6214 "Dictionary members cannot be [LegacyNullToEmptyString]",
6215 [self.location],
6217 if self.type.isObservableArray():
6218 raise WebIDLError(
6219 "%s cannot have an ObservableArray type"
6220 % ("Dictionary members" if self.dictionaryMember else "Arguments"),
6221 [self.location],
6223 # Now do the coercing thing; this needs to happen after the
6224 # above creation of a default value.
6225 if self.defaultValue:
6226 self.defaultValue = self.defaultValue.coerceToType(self.type, self.location)
6227 assert self.defaultValue
6229 def allowTreatNonCallableAsNull(self):
6230 return self._allowTreatNonCallableAsNull
6232 def _getDependentObjects(self):
6233 deps = set([self.type])
6234 if self.defaultValue:
6235 deps.add(self.defaultValue)
6236 return deps
6238 def canHaveMissingValue(self):
6239 return self.optional and not self.defaultValue
6242 class IDLCallback(IDLObjectWithScope):
6243 __slots__ = (
6244 "_returnType",
6245 "_arguments",
6246 "_treatNonCallableAsNull",
6247 "_treatNonObjectAsNull",
6248 "_isRunScriptBoundary",
6249 "_isConstructor",
6252 def __init__(
6253 self, location, parentScope, identifier, returnType, arguments, isConstructor
6255 assert isinstance(returnType, IDLType)
6257 self._returnType = returnType
6258 # Clone the list
6259 self._arguments = list(arguments)
6261 IDLObjectWithScope.__init__(self, location, parentScope, identifier)
6263 for returnType, arguments in self.signatures():
6264 for argument in arguments:
6265 argument.resolve(self)
6267 self._treatNonCallableAsNull = False
6268 self._treatNonObjectAsNull = False
6269 self._isRunScriptBoundary = False
6270 self._isConstructor = isConstructor
6272 def isCallback(self):
6273 return True
6275 def isConstructor(self):
6276 return self._isConstructor
6278 def signatures(self):
6279 return [(self._returnType, self._arguments)]
6281 def finish(self, scope):
6282 if not self._returnType.isComplete():
6283 type = self._returnType.complete(scope)
6285 assert not isinstance(type, IDLUnresolvedType)
6286 assert not isinstance(type, IDLTypedefType)
6287 assert not isinstance(type.name, IDLUnresolvedIdentifier)
6288 self._returnType = type
6290 for argument in self._arguments:
6291 if argument.type.isComplete():
6292 continue
6294 type = argument.type.complete(scope)
6296 assert not isinstance(type, IDLUnresolvedType)
6297 assert not isinstance(type, IDLTypedefType)
6298 assert not isinstance(type.name, IDLUnresolvedIdentifier)
6299 argument.type = type
6301 def validate(self):
6302 for argument in self._arguments:
6303 if argument.type.isUndefined():
6304 raise WebIDLError(
6305 "undefined must not be used as the type of an argument in any circumstance",
6306 [self.location],
6309 def addExtendedAttributes(self, attrs):
6310 unhandledAttrs = []
6311 for attr in attrs:
6312 if attr.identifier() == "TreatNonCallableAsNull":
6313 self._treatNonCallableAsNull = True
6314 elif attr.identifier() == "LegacyTreatNonObjectAsNull":
6315 if self._isConstructor:
6316 raise WebIDLError(
6317 "[LegacyTreatNonObjectAsNull] is not supported "
6318 "on constructors",
6319 [self.location],
6321 self._treatNonObjectAsNull = True
6322 elif attr.identifier() == "MOZ_CAN_RUN_SCRIPT_BOUNDARY":
6323 if self._isConstructor:
6324 raise WebIDLError(
6325 "[MOZ_CAN_RUN_SCRIPT_BOUNDARY] is not "
6326 "permitted on constructors",
6327 [self.location],
6329 self._isRunScriptBoundary = True
6330 else:
6331 unhandledAttrs.append(attr)
6332 if self._treatNonCallableAsNull and self._treatNonObjectAsNull:
6333 raise WebIDLError(
6334 "Cannot specify both [TreatNonCallableAsNull] "
6335 "and [LegacyTreatNonObjectAsNull]",
6336 [self.location],
6338 if len(unhandledAttrs) != 0:
6339 IDLType.addExtendedAttributes(self, unhandledAttrs)
6341 def _getDependentObjects(self):
6342 return set([self._returnType] + self._arguments)
6344 def isRunScriptBoundary(self):
6345 return self._isRunScriptBoundary
6348 class IDLCallbackType(IDLType):
6349 __slots__ = ("callback",)
6351 def __init__(self, location, callback):
6352 IDLType.__init__(self, location, callback.identifier.name)
6353 self.callback = callback
6355 def isCallback(self):
6356 return True
6358 def tag(self):
6359 return IDLType.Tags.callback
6361 def isDistinguishableFrom(self, other):
6362 if other.isPromise():
6363 return False
6364 if other.isUnion():
6365 # Just forward to the union; it'll deal
6366 return other.isDistinguishableFrom(self)
6367 # Callbacks without `LegacyTreatNonObjectAsNull` are distinguishable from Dictionary likes
6368 if other.isDictionaryLike():
6369 return not self.callback._treatNonObjectAsNull
6370 return (
6371 other.isUndefined()
6372 or other.isPrimitive()
6373 or other.isString()
6374 or other.isEnum()
6375 or other.isNonCallbackInterface()
6376 or other.isSequence()
6379 def _getDependentObjects(self):
6380 return self.callback._getDependentObjects()
6383 class IDLMethodOverload:
6385 A class that represents a single overload of a WebIDL method. This is not
6386 quite the same as an element of the "effective overload set" in the spec,
6387 because separate IDLMethodOverloads are not created based on arguments being
6388 optional. Rather, when multiple methods have the same name, there is an
6389 IDLMethodOverload for each one, all hanging off an IDLMethod representing
6390 the full set of overloads.
6393 __slots__ = "returnType", "arguments", "location"
6395 def __init__(self, returnType, arguments, location):
6396 self.returnType = returnType
6397 # Clone the list of arguments, just in case
6398 self.arguments = list(arguments)
6399 self.location = location
6401 def _getDependentObjects(self):
6402 deps = set(self.arguments)
6403 deps.add(self.returnType)
6404 return deps
6406 def includesRestrictedFloatArgument(self):
6407 return any(arg.type.includesRestrictedFloat() for arg in self.arguments)
6410 class IDLMethod(IDLInterfaceMember, IDLScope):
6411 Special = enum(
6412 "Getter", "Setter", "Deleter", "LegacyCaller", base=IDLInterfaceMember.Special
6415 NamedOrIndexed = enum("Neither", "Named", "Indexed")
6417 __slots__ = (
6418 "_hasOverloads",
6419 "_overloads",
6420 "_static",
6421 "_getter",
6422 "_setter",
6423 "_deleter",
6424 "_legacycaller",
6425 "_stringifier",
6426 "maplikeOrSetlikeOrIterable",
6427 "_htmlConstructor",
6428 "underlyingAttr",
6429 "_specialType",
6430 "_legacyUnforgeable",
6431 "dependsOn",
6432 "affects",
6433 "aliases",
6436 def __init__(
6437 self,
6438 location,
6439 identifier,
6440 returnType,
6441 arguments,
6442 static=False,
6443 getter=False,
6444 setter=False,
6445 deleter=False,
6446 specialType=NamedOrIndexed.Neither,
6447 legacycaller=False,
6448 stringifier=False,
6449 maplikeOrSetlikeOrIterable=None,
6450 underlyingAttr=None,
6452 # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up.
6453 IDLInterfaceMember.__init__(
6454 self, location, identifier, IDLInterfaceMember.Tags.Method
6457 self._hasOverloads = False
6459 assert isinstance(returnType, IDLType)
6461 # self._overloads is a list of IDLMethodOverloads
6462 self._overloads = [IDLMethodOverload(returnType, arguments, location)]
6464 assert isinstance(static, bool)
6465 self._static = static
6466 assert isinstance(getter, bool)
6467 self._getter = getter
6468 assert isinstance(setter, bool)
6469 self._setter = setter
6470 assert isinstance(deleter, bool)
6471 self._deleter = deleter
6472 assert isinstance(legacycaller, bool)
6473 self._legacycaller = legacycaller
6474 assert isinstance(stringifier, bool)
6475 self._stringifier = stringifier
6476 assert maplikeOrSetlikeOrIterable is None or isinstance(
6477 maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase
6479 self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable
6480 self._htmlConstructor = False
6481 self.underlyingAttr = underlyingAttr
6482 self._specialType = specialType
6483 self._legacyUnforgeable = False
6484 self.dependsOn = "Everything"
6485 self.affects = "Everything"
6486 self.aliases = []
6488 if static and identifier.name == "prototype":
6489 raise WebIDLError(
6490 "The identifier of a static operation must not be 'prototype'",
6491 [location],
6494 self.assertSignatureConstraints()
6496 def __str__(self):
6497 return "Method '%s'" % self.identifier
6499 def assertSignatureConstraints(self):
6500 if self._getter or self._deleter:
6501 assert len(self._overloads) == 1
6502 overload = self._overloads[0]
6503 arguments = overload.arguments
6504 assert len(arguments) == 1
6505 assert (
6506 arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.domstring]
6507 or arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]
6509 assert not arguments[0].optional and not arguments[0].variadic
6510 assert not self._getter or not overload.returnType.isUndefined()
6512 if self._setter:
6513 assert len(self._overloads) == 1
6514 arguments = self._overloads[0].arguments
6515 assert len(arguments) == 2
6516 assert (
6517 arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.domstring]
6518 or arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]
6520 assert not arguments[0].optional and not arguments[0].variadic
6521 assert not arguments[1].optional and not arguments[1].variadic
6523 if self._stringifier:
6524 assert len(self._overloads) == 1
6525 overload = self._overloads[0]
6526 assert len(overload.arguments) == 0
6527 if not self.underlyingAttr:
6528 assert (
6529 overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring]
6532 def isStatic(self):
6533 return self._static
6535 def forceStatic(self):
6536 self._static = True
6538 def isGetter(self):
6539 return self._getter
6541 def isSetter(self):
6542 return self._setter
6544 def isDeleter(self):
6545 return self._deleter
6547 def isNamed(self):
6548 assert (
6549 self._specialType == IDLMethod.NamedOrIndexed.Named
6550 or self._specialType == IDLMethod.NamedOrIndexed.Indexed
6552 return self._specialType == IDLMethod.NamedOrIndexed.Named
6554 def isIndexed(self):
6555 assert (
6556 self._specialType == IDLMethod.NamedOrIndexed.Named
6557 or self._specialType == IDLMethod.NamedOrIndexed.Indexed
6559 return self._specialType == IDLMethod.NamedOrIndexed.Indexed
6561 def isLegacycaller(self):
6562 return self._legacycaller
6564 def isStringifier(self):
6565 return self._stringifier
6567 def isToJSON(self):
6568 return self.identifier.name == "toJSON"
6570 def isDefaultToJSON(self):
6571 return self.isToJSON() and self.getExtendedAttribute("Default")
6573 def isMaplikeOrSetlikeOrIterableMethod(self):
6575 True if this method was generated as part of a
6576 maplike/setlike/etc interface (e.g. has/get methods)
6578 return self.maplikeOrSetlikeOrIterable is not None
6580 def isSpecial(self):
6581 return (
6582 self.isGetter()
6583 or self.isSetter()
6584 or self.isDeleter()
6585 or self.isLegacycaller()
6586 or self.isStringifier()
6589 def isHTMLConstructor(self):
6590 return self._htmlConstructor
6592 def hasOverloads(self):
6593 return self._hasOverloads
6595 def isIdentifierLess(self):
6597 True if the method name started with __, and if the method is not a
6598 maplike/setlike method. Interfaces with maplike/setlike will generate
6599 methods starting with __ for chrome only backing object access in JS
6600 implemented interfaces, so while these functions use what is considered
6601 an non-identifier name, they actually DO have an identifier.
6603 return (
6604 self.identifier.name[:2] == "__"
6605 and not self.isMaplikeOrSetlikeOrIterableMethod()
6608 def resolve(self, parentScope):
6609 assert isinstance(parentScope, IDLScope)
6610 IDLObjectWithIdentifier.resolve(self, parentScope)
6611 IDLScope.__init__(self, self.location, parentScope, self.identifier)
6612 for returnType, arguments in self.signatures():
6613 for argument in arguments:
6614 argument.resolve(self)
6616 def addOverload(self, method):
6617 assert len(method._overloads) == 1
6619 if self._extendedAttrDict != method._extendedAttrDict:
6620 extendedAttrDiff = set(self._extendedAttrDict.keys()) ^ set(
6621 method._extendedAttrDict.keys()
6624 if extendedAttrDiff == {"LenientFloat"}:
6625 if "LenientFloat" not in self._extendedAttrDict:
6626 for overload in self._overloads:
6627 if overload.includesRestrictedFloatArgument():
6628 raise WebIDLError(
6629 "Restricted float behavior differs on different "
6630 "overloads of %s" % method.identifier,
6631 [overload.location, method.location],
6633 self._extendedAttrDict["LenientFloat"] = method._extendedAttrDict[
6634 "LenientFloat"
6636 elif method._overloads[0].includesRestrictedFloatArgument():
6637 raise WebIDLError(
6638 "Restricted float behavior differs on different "
6639 "overloads of %s" % method.identifier,
6640 [self.location, method.location],
6642 else:
6643 raise WebIDLError(
6644 "Extended attributes differ on different "
6645 "overloads of %s" % method.identifier,
6646 [self.location, method.location],
6649 self._overloads.extend(method._overloads)
6651 self._hasOverloads = True
6653 if self.isStatic() != method.isStatic():
6654 raise WebIDLError(
6655 "Overloaded identifier %s appears with different values of the 'static' attribute"
6656 % method.identifier,
6657 [method.location],
6660 if self.isLegacycaller() != method.isLegacycaller():
6661 raise WebIDLError(
6663 "Overloaded identifier %s appears with different "
6664 "values of the 'legacycaller' attribute" % method.identifier
6666 [method.location],
6669 # Can't overload special things!
6670 if (
6671 self.isGetter()
6672 or method.isGetter()
6673 or self.isSetter()
6674 or method.isSetter()
6675 or self.isDeleter()
6676 or method.isDeleter()
6677 or self.isStringifier()
6678 or method.isStringifier()
6680 raise WebIDLError(
6681 ("Can't overload a special operation"),
6682 [self.location, method.location],
6684 if self.isHTMLConstructor() or method.isHTMLConstructor():
6685 raise WebIDLError(
6687 "An interface must contain only a single operation annotated with HTMLConstructor, and no others"
6689 [self.location, method.location],
6692 return self
6694 def signatures(self):
6695 return [
6696 (overload.returnType, overload.arguments) for overload in self._overloads
6699 def finish(self, scope):
6700 IDLInterfaceMember.finish(self, scope)
6702 for overload in self._overloads:
6703 returnType = overload.returnType
6704 if not returnType.isComplete():
6705 returnType = returnType.complete(scope)
6706 assert not isinstance(returnType, IDLUnresolvedType)
6707 assert not isinstance(returnType, IDLTypedefType)
6708 assert not isinstance(returnType.name, IDLUnresolvedIdentifier)
6709 overload.returnType = returnType
6711 for argument in overload.arguments:
6712 if not argument.isComplete():
6713 argument.complete(scope)
6714 assert argument.type.isComplete()
6716 # Now compute various information that will be used by the
6717 # WebIDL overload resolution algorithm.
6718 self.maxArgCount = max(len(s[1]) for s in self.signatures())
6719 self.allowedArgCounts = [
6721 for i in range(self.maxArgCount + 1)
6722 if len(self.signaturesForArgCount(i)) != 0
6725 def validate(self):
6726 IDLInterfaceMember.validate(self)
6728 # Make sure our overloads are properly distinguishable and don't have
6729 # different argument types before the distinguishing args.
6730 for argCount in self.allowedArgCounts:
6731 possibleOverloads = self.overloadsForArgCount(argCount)
6732 if len(possibleOverloads) == 1:
6733 continue
6734 distinguishingIndex = self.distinguishingIndexForArgCount(argCount)
6735 for idx in range(distinguishingIndex):
6736 firstSigType = possibleOverloads[0].arguments[idx].type
6737 for overload in possibleOverloads[1:]:
6738 if overload.arguments[idx].type != firstSigType:
6739 raise WebIDLError(
6740 "Signatures for method '%s' with %d arguments have "
6741 "different types of arguments at index %d, which "
6742 "is before distinguishing index %d"
6744 self.identifier.name,
6745 argCount,
6746 idx,
6747 distinguishingIndex,
6749 [self.location, overload.location],
6752 overloadWithPromiseReturnType = None
6753 overloadWithoutPromiseReturnType = None
6754 for overload in self._overloads:
6755 returnType = overload.returnType
6756 if not returnType.unroll().isExposedInAllOf(self.exposureSet):
6757 raise WebIDLError(
6758 "Overload returns a type that is not exposed "
6759 "everywhere where the method is exposed",
6760 [overload.location],
6763 variadicArgument = None
6765 arguments = overload.arguments
6766 for idx, argument in enumerate(arguments):
6767 assert argument.type.isComplete()
6769 if (
6770 argument.type.isDictionary()
6771 and argument.type.unroll().inner.canBeEmpty()
6772 ) or (
6773 argument.type.isUnion()
6774 and argument.type.unroll().hasPossiblyEmptyDictionaryType()
6776 # Optional dictionaries and unions containing optional
6777 # dictionaries at the end of the list or followed by
6778 # optional arguments must be optional.
6779 if not argument.optional and all(
6780 arg.optional for arg in arguments[idx + 1 :]
6782 raise WebIDLError(
6783 "Dictionary argument without any "
6784 "required fields or union argument "
6785 "containing such dictionary not "
6786 "followed by a required argument "
6787 "must be optional",
6788 [argument.location],
6791 if not argument.defaultValue and all(
6792 arg.optional for arg in arguments[idx + 1 :]
6794 raise WebIDLError(
6795 "Dictionary argument without any "
6796 "required fields or union argument "
6797 "containing such dictionary not "
6798 "followed by a required argument "
6799 "must have a default value",
6800 [argument.location],
6803 # An argument cannot be a nullable dictionary or a
6804 # nullable union containing a dictionary.
6805 if argument.type.nullable() and (
6806 argument.type.isDictionary()
6807 or (
6808 argument.type.isUnion()
6809 and argument.type.unroll().hasDictionaryType()
6812 raise WebIDLError(
6813 "An argument cannot be a nullable "
6814 "dictionary or nullable union "
6815 "containing a dictionary",
6816 [argument.location],
6819 # Only the last argument can be variadic
6820 if variadicArgument:
6821 raise WebIDLError(
6822 "Variadic argument is not last argument",
6823 [variadicArgument.location],
6825 if argument.variadic:
6826 variadicArgument = argument
6828 if returnType.isPromise():
6829 overloadWithPromiseReturnType = overload
6830 else:
6831 overloadWithoutPromiseReturnType = overload
6833 # Make sure either all our overloads return Promises or none do
6834 if overloadWithPromiseReturnType and overloadWithoutPromiseReturnType:
6835 raise WebIDLError(
6836 "We have overloads with both Promise and non-Promise return types",
6838 overloadWithPromiseReturnType.location,
6839 overloadWithoutPromiseReturnType.location,
6843 if overloadWithPromiseReturnType and self._legacycaller:
6844 raise WebIDLError(
6845 "May not have a Promise return type for a legacycaller.",
6846 [overloadWithPromiseReturnType.location],
6849 if self.getExtendedAttribute("StaticClassOverride") and not (
6850 self.identifier.scope.isJSImplemented() and self.isStatic()
6852 raise WebIDLError(
6853 "StaticClassOverride can be applied to static"
6854 " methods on JS-implemented classes only.",
6855 [self.location],
6858 # Ensure that toJSON methods satisfy the spec constraints on them.
6859 if self.identifier.name == "toJSON":
6860 if len(self.signatures()) != 1:
6861 raise WebIDLError(
6862 "toJSON method has multiple overloads",
6863 [self._overloads[0].location, self._overloads[1].location],
6865 if len(self.signatures()[0][1]) != 0:
6866 raise WebIDLError("toJSON method has arguments", [self.location])
6867 if not self.signatures()[0][0].isJSONType():
6868 raise WebIDLError(
6869 "toJSON method has non-JSON return type", [self.location]
6872 def overloadsForArgCount(self, argc):
6873 return [
6874 overload
6875 for overload in self._overloads
6876 if len(overload.arguments) == argc
6877 or (
6878 len(overload.arguments) > argc
6879 and all(arg.optional for arg in overload.arguments[argc:])
6881 or (
6882 len(overload.arguments) < argc
6883 and len(overload.arguments) > 0
6884 and overload.arguments[-1].variadic
6888 def signaturesForArgCount(self, argc):
6889 return [
6890 (overload.returnType, overload.arguments)
6891 for overload in self.overloadsForArgCount(argc)
6894 def locationsForArgCount(self, argc):
6895 return [overload.location for overload in self.overloadsForArgCount(argc)]
6897 def distinguishingIndexForArgCount(self, argc):
6898 def isValidDistinguishingIndex(idx, signatures):
6899 for firstSigIndex, (firstRetval, firstArgs) in enumerate(signatures[:-1]):
6900 for secondRetval, secondArgs in signatures[firstSigIndex + 1 :]:
6901 if idx < len(firstArgs):
6902 firstType = firstArgs[idx].type
6903 else:
6904 assert firstArgs[-1].variadic
6905 firstType = firstArgs[-1].type
6906 if idx < len(secondArgs):
6907 secondType = secondArgs[idx].type
6908 else:
6909 assert secondArgs[-1].variadic
6910 secondType = secondArgs[-1].type
6911 if not firstType.isDistinguishableFrom(secondType):
6912 return False
6913 return True
6915 signatures = self.signaturesForArgCount(argc)
6916 for idx in range(argc):
6917 if isValidDistinguishingIndex(idx, signatures):
6918 return idx
6919 # No valid distinguishing index. Time to throw
6920 locations = self.locationsForArgCount(argc)
6921 raise WebIDLError(
6922 "Signatures with %d arguments for method '%s' are not "
6923 "distinguishable" % (argc, self.identifier.name),
6924 locations,
6927 def handleExtendedAttribute(self, attr):
6928 identifier = attr.identifier()
6929 if (
6930 identifier == "GetterThrows"
6931 or identifier == "SetterThrows"
6932 or identifier == "GetterCanOOM"
6933 or identifier == "SetterCanOOM"
6934 or identifier == "SetterNeedsSubjectPrincipal"
6935 or identifier == "GetterNeedsSubjectPrincipal"
6937 raise WebIDLError(
6938 "Methods must not be flagged as [%s]" % identifier,
6939 [attr.location, self.location],
6941 elif identifier == "LegacyUnforgeable":
6942 if self.isStatic():
6943 raise WebIDLError(
6944 "[LegacyUnforgeable] is only allowed on non-static methods",
6945 [attr.location, self.location],
6947 self._legacyUnforgeable = True
6948 elif identifier == "SameObject":
6949 raise WebIDLError(
6950 "Methods must not be flagged as [SameObject]",
6951 [attr.location, self.location],
6953 elif identifier == "Constant":
6954 raise WebIDLError(
6955 "Methods must not be flagged as [Constant]",
6956 [attr.location, self.location],
6958 elif identifier == "PutForwards":
6959 raise WebIDLError(
6960 "Only attributes support [PutForwards]", [attr.location, self.location]
6962 elif identifier == "LegacyLenientSetter":
6963 raise WebIDLError(
6964 "Only attributes support [LegacyLenientSetter]",
6965 [attr.location, self.location],
6967 elif identifier == "LenientFloat":
6968 # This is called before we've done overload resolution
6969 overloads = self._overloads
6970 assert len(overloads) == 1
6971 if not overloads[0].returnType.isUndefined():
6972 raise WebIDLError(
6973 "[LenientFloat] used on a non-undefined method",
6974 [attr.location, self.location],
6976 if not overloads[0].includesRestrictedFloatArgument():
6977 raise WebIDLError(
6978 "[LenientFloat] used on an operation with no "
6979 "restricted float type arguments",
6980 [attr.location, self.location],
6982 elif identifier == "Exposed":
6983 convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
6984 elif (
6985 identifier == "CrossOriginCallable"
6986 or identifier == "WebGLHandlesContextLoss"
6988 # Known no-argument attributes.
6989 if not attr.noArguments():
6990 raise WebIDLError(
6991 "[%s] must take no arguments" % identifier, [attr.location]
6993 if identifier == "CrossOriginCallable" and self.isStatic():
6994 raise WebIDLError(
6995 "[CrossOriginCallable] is only allowed on non-static attributes",
6996 [attr.location, self.location],
6998 elif identifier == "Pure":
6999 if not attr.noArguments():
7000 raise WebIDLError("[Pure] must take no arguments", [attr.location])
7001 self._setDependsOn("DOMState")
7002 self._setAffects("Nothing")
7003 elif identifier == "Affects":
7004 if not attr.hasValue():
7005 raise WebIDLError("[Affects] takes an identifier", [attr.location])
7006 self._setAffects(attr.value())
7007 elif identifier == "DependsOn":
7008 if not attr.hasValue():
7009 raise WebIDLError("[DependsOn] takes an identifier", [attr.location])
7010 self._setDependsOn(attr.value())
7011 elif identifier == "Alias":
7012 if not attr.hasValue():
7013 raise WebIDLError(
7014 "[Alias] takes an identifier or string", [attr.location]
7016 self._addAlias(attr.value())
7017 elif identifier == "UseCounter":
7018 if self.isSpecial():
7019 raise WebIDLError(
7020 "[UseCounter] must not be used on a special operation",
7021 [attr.location, self.location],
7023 elif identifier == "Unscopable":
7024 if not attr.noArguments():
7025 raise WebIDLError(
7026 "[Unscopable] must take no arguments", [attr.location]
7028 if self.isStatic():
7029 raise WebIDLError(
7030 "[Unscopable] is only allowed on non-static "
7031 "attributes and operations",
7032 [attr.location, self.location],
7034 elif identifier == "CEReactions":
7035 if not attr.noArguments():
7036 raise WebIDLError(
7037 "[CEReactions] must take no arguments", [attr.location]
7040 if self.isSpecial() and not self.isSetter() and not self.isDeleter():
7041 raise WebIDLError(
7042 "[CEReactions] is only allowed on operation, "
7043 "attribute, setter, and deleter",
7044 [attr.location, self.location],
7046 elif identifier == "Default":
7047 if not attr.noArguments():
7048 raise WebIDLError("[Default] must take no arguments", [attr.location])
7050 if not self.isToJSON():
7051 raise WebIDLError(
7052 "[Default] is only allowed on toJSON operations",
7053 [attr.location, self.location],
7056 if self.signatures()[0][0] != BuiltinTypes[IDLBuiltinType.Types.object]:
7057 raise WebIDLError(
7058 "The return type of the default toJSON "
7059 "operation must be 'object'",
7060 [attr.location, self.location],
7062 elif (
7063 identifier == "Throws"
7064 or identifier == "CanOOM"
7065 or identifier == "NewObject"
7066 or identifier == "ChromeOnly"
7067 or identifier == "Pref"
7068 or identifier == "Deprecated"
7069 or identifier == "Func"
7070 or identifier == "Trial"
7071 or identifier == "SecureContext"
7072 or identifier == "BinaryName"
7073 or identifier == "NeedsSubjectPrincipal"
7074 or identifier == "NeedsCallerType"
7075 or identifier == "StaticClassOverride"
7076 or identifier == "NonEnumerable"
7077 or identifier == "Unexposed"
7078 or identifier == "WebExtensionStub"
7080 # Known attributes that we don't need to do anything with here
7081 pass
7082 else:
7083 raise WebIDLError(
7084 "Unknown extended attribute %s on method" % identifier, [attr.location]
7086 IDLInterfaceMember.handleExtendedAttribute(self, attr)
7088 def returnsPromise(self):
7089 return self._overloads[0].returnType.isPromise()
7091 def isLegacyUnforgeable(self):
7092 return self._legacyUnforgeable
7094 def _getDependentObjects(self):
7095 deps = set()
7096 for overload in self._overloads:
7097 deps.update(overload._getDependentObjects())
7098 return deps
7101 class IDLConstructor(IDLMethod):
7102 __slots__ = (
7103 "_initLocation",
7104 "_initArgs",
7105 "_initName",
7106 "_inited",
7107 "_initExtendedAttrs",
7110 def __init__(self, location, args, name):
7111 # We can't actually init our IDLMethod yet, because we do not know the
7112 # return type yet. Just save the info we have for now and we will init
7113 # it later.
7114 self._initLocation = location
7115 self._initArgs = args
7116 self._initName = name
7117 self._inited = False
7118 self._initExtendedAttrs = []
7120 def addExtendedAttributes(self, attrs):
7121 if self._inited:
7122 return IDLMethod.addExtendedAttributes(self, attrs)
7123 self._initExtendedAttrs.extend(attrs)
7125 def handleExtendedAttribute(self, attr):
7126 identifier = attr.identifier()
7127 if (
7128 identifier == "BinaryName"
7129 or identifier == "ChromeOnly"
7130 or identifier == "NewObject"
7131 or identifier == "SecureContext"
7132 or identifier == "Throws"
7133 or identifier == "Func"
7134 or identifier == "Trial"
7135 or identifier == "Pref"
7136 or identifier == "UseCounter"
7138 IDLMethod.handleExtendedAttribute(self, attr)
7139 elif identifier == "HTMLConstructor":
7140 if not attr.noArguments():
7141 raise WebIDLError(
7142 "[HTMLConstructor] must take no arguments", [attr.location]
7144 # We shouldn't end up here for legacy factory functions.
7145 assert self.identifier.name == "constructor"
7147 if any(len(sig[1]) != 0 for sig in self.signatures()):
7148 raise WebIDLError(
7149 "[HTMLConstructor] must not be applied to a "
7150 "constructor operation that has arguments.",
7151 [attr.location],
7153 self._htmlConstructor = True
7154 else:
7155 raise WebIDLError(
7156 "Unknown extended attribute %s on method" % identifier, [attr.location]
7159 def reallyInit(self, parentInterface):
7160 name = self._initName
7161 location = self._initLocation
7162 identifier = IDLUnresolvedIdentifier(location, name, allowForbidden=True)
7163 retType = IDLWrapperType(parentInterface.location, parentInterface)
7164 IDLMethod.__init__(
7165 self, location, identifier, retType, self._initArgs, static=True
7167 self._inited = True
7168 # Propagate through whatever extended attributes we already had
7169 self.addExtendedAttributes(self._initExtendedAttrs)
7170 self._initExtendedAttrs = []
7171 # Constructors are always NewObject. Whether they throw or not is
7172 # indicated by [Throws] annotations in the usual way.
7173 self.addExtendedAttributes(
7174 [IDLExtendedAttribute(self.location, ("NewObject",))]
7178 class IDLIncludesStatement(IDLObject):
7179 __slots__ = ("interface", "mixin", "_finished")
7181 def __init__(self, location, interface, mixin):
7182 IDLObject.__init__(self, location)
7183 self.interface = interface
7184 self.mixin = mixin
7185 self._finished = False
7187 def finish(self, scope):
7188 if self._finished:
7189 return
7190 self._finished = True
7191 assert isinstance(self.interface, IDLIdentifierPlaceholder)
7192 assert isinstance(self.mixin, IDLIdentifierPlaceholder)
7193 interface = self.interface.finish(scope)
7194 mixin = self.mixin.finish(scope)
7195 # NOTE: we depend on not setting self.interface and
7196 # self.mixin here to keep track of the original
7197 # locations.
7198 if not isinstance(interface, IDLInterface):
7199 raise WebIDLError(
7200 "Left-hand side of 'includes' is not an interface",
7201 [self.interface.location, interface.location],
7203 if interface.isCallback():
7204 raise WebIDLError(
7205 "Left-hand side of 'includes' is a callback interface",
7206 [self.interface.location, interface.location],
7208 if not isinstance(mixin, IDLInterfaceMixin):
7209 raise WebIDLError(
7210 "Right-hand side of 'includes' is not an interface mixin",
7211 [self.mixin.location, mixin.location],
7214 mixin.actualExposureGlobalNames.update(interface._exposureGlobalNames)
7216 interface.addIncludedMixin(mixin)
7217 self.interface = interface
7218 self.mixin = mixin
7220 def validate(self):
7221 pass
7223 def addExtendedAttributes(self, attrs):
7224 if len(attrs) != 0:
7225 raise WebIDLError(
7226 "There are no extended attributes that are "
7227 "allowed on includes statements",
7228 [attrs[0].location, self.location],
7232 class IDLExtendedAttribute(IDLObject):
7234 A class to represent IDL extended attributes so we can give them locations
7237 __slots__ = ("_tuple",)
7239 def __init__(self, location, tuple):
7240 IDLObject.__init__(self, location)
7241 self._tuple = tuple
7243 def identifier(self):
7244 return self._tuple[0]
7246 def noArguments(self):
7247 return len(self._tuple) == 1
7249 def hasValue(self):
7250 return len(self._tuple) >= 2 and isinstance(self._tuple[1], str)
7252 def value(self):
7253 assert self.hasValue()
7254 return self._tuple[1]
7256 def hasArgs(self):
7257 return (
7258 len(self._tuple) == 2
7259 and isinstance(self._tuple[1], list)
7260 or len(self._tuple) == 3
7263 def args(self):
7264 assert self.hasArgs()
7265 # Our args are our last element
7266 return self._tuple[-1]
7268 def listValue(self):
7270 Backdoor for storing random data in _extendedAttrDict
7272 return list(self._tuple)[1:]
7275 # Parser
7278 class Tokenizer(object):
7279 tokens = ["INTEGER", "FLOATLITERAL", "IDENTIFIER", "STRING", "COMMENTS", "OTHER"]
7281 def t_FLOATLITERAL(self, t):
7282 r"(-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+|Infinity))|NaN"
7283 t.value = float(t.value)
7284 return t
7286 def t_INTEGER(self, t):
7287 r"-?(0([0-7]+|[Xx][0-9A-Fa-f]+)?|[1-9][0-9]*)"
7288 try:
7289 # Can't use int(), because that doesn't handle octal properly.
7290 t.value = parseInt(t.value)
7291 except Exception:
7292 raise WebIDLError(
7293 "Invalid integer literal",
7295 Location(
7296 lexer=self.lexer,
7297 lineno=self.lexer.lineno,
7298 lexpos=self.lexer.lexpos,
7299 filename=self._filename,
7303 return t
7305 def t_IDENTIFIER(self, t):
7306 r"[_-]?[A-Za-z][0-9A-Z_a-z-]*"
7307 t.type = self.keywords.get(t.value, "IDENTIFIER")
7308 return t
7310 def t_STRING(self, t):
7311 r'"[^"]*"'
7312 t.value = t.value[1:-1]
7313 return t
7315 t_ignore = "\t\n\r "
7317 def t_COMMENTS(self, t):
7318 r"//[^\n]*|/\*(?s:.)*?\*/"
7319 pass
7321 def t_ELLIPSIS(self, t):
7322 r"\.\.\."
7323 t.type = "ELLIPSIS"
7324 return t
7326 def t_OTHER(self, t):
7327 r"[^0-9A-Z_a-z]"
7328 t.type = self.keywords.get(t.value, "OTHER")
7329 return t
7331 keywords = {
7332 "interface": "INTERFACE",
7333 "partial": "PARTIAL",
7334 "mixin": "MIXIN",
7335 "dictionary": "DICTIONARY",
7336 "exception": "EXCEPTION",
7337 "enum": "ENUM",
7338 "callback": "CALLBACK",
7339 "typedef": "TYPEDEF",
7340 "includes": "INCLUDES",
7341 "const": "CONST",
7342 "null": "NULL",
7343 "true": "TRUE",
7344 "false": "FALSE",
7345 "serializer": "SERIALIZER",
7346 "stringifier": "STRINGIFIER",
7347 "unrestricted": "UNRESTRICTED",
7348 "attribute": "ATTRIBUTE",
7349 "readonly": "READONLY",
7350 "inherit": "INHERIT",
7351 "static": "STATIC",
7352 "getter": "GETTER",
7353 "setter": "SETTER",
7354 "deleter": "DELETER",
7355 "legacycaller": "LEGACYCALLER",
7356 "optional": "OPTIONAL",
7357 "...": "ELLIPSIS",
7358 "::": "SCOPE",
7359 "DOMString": "DOMSTRING",
7360 "ByteString": "BYTESTRING",
7361 "USVString": "USVSTRING",
7362 "JSString": "JSSTRING",
7363 "UTF8String": "UTF8STRING",
7364 "any": "ANY",
7365 "boolean": "BOOLEAN",
7366 "byte": "BYTE",
7367 "double": "DOUBLE",
7368 "float": "FLOAT",
7369 "long": "LONG",
7370 "object": "OBJECT",
7371 "ObservableArray": "OBSERVABLEARRAY",
7372 "octet": "OCTET",
7373 "Promise": "PROMISE",
7374 "required": "REQUIRED",
7375 "sequence": "SEQUENCE",
7376 "record": "RECORD",
7377 "short": "SHORT",
7378 "unsigned": "UNSIGNED",
7379 "undefined": "UNDEFINED",
7380 ":": "COLON",
7381 ";": "SEMICOLON",
7382 "{": "LBRACE",
7383 "}": "RBRACE",
7384 "(": "LPAREN",
7385 ")": "RPAREN",
7386 "[": "LBRACKET",
7387 "]": "RBRACKET",
7388 "?": "QUESTIONMARK",
7389 "*": "ASTERISK",
7390 ",": "COMMA",
7391 "=": "EQUALS",
7392 "<": "LT",
7393 ">": "GT",
7394 "ArrayBuffer": "ARRAYBUFFER",
7395 "or": "OR",
7396 "maplike": "MAPLIKE",
7397 "setlike": "SETLIKE",
7398 "iterable": "ITERABLE",
7399 "namespace": "NAMESPACE",
7400 "constructor": "CONSTRUCTOR",
7401 "symbol": "SYMBOL",
7402 "async": "ASYNC",
7405 tokens.extend(keywords.values())
7407 def t_error(self, t):
7408 raise WebIDLError(
7409 "Unrecognized Input",
7411 Location(
7412 lexer=self.lexer,
7413 lineno=self.lexer.lineno,
7414 lexpos=self.lexer.lexpos,
7415 filename=self._filename,
7420 def __init__(self, outputdir, lexer=None):
7421 if lexer:
7422 self.lexer = lexer
7423 else:
7424 self.lexer = lex.lex(object=self)
7427 class SqueakyCleanLogger(object):
7428 errorWhitelist = [
7429 # Web IDL defines the COMMENTS token, but doesn't actually
7430 # use it ... so far.
7431 "Token 'COMMENTS' defined, but not used",
7432 # And that means we have an unused token
7433 "There is 1 unused token",
7434 # Web IDL defines a OtherOrComma rule that's only used in
7435 # ExtendedAttributeInner, which we don't use yet.
7436 "Rule 'OtherOrComma' defined, but not used",
7437 # And an unused rule
7438 "There is 1 unused rule",
7439 # And the OtherOrComma grammar symbol is unreachable.
7440 "Symbol 'OtherOrComma' is unreachable",
7441 # Which means the Other symbol is unreachable.
7442 "Symbol 'Other' is unreachable",
7445 def __init__(self):
7446 self.errors = []
7448 def debug(self, msg, *args, **kwargs):
7449 pass
7451 info = debug
7453 def warning(self, msg, *args, **kwargs):
7454 if (
7455 msg == "%s:%d: Rule %r defined, but not used"
7456 or msg == "%s:%d: Rule '%s' defined, but not used"
7458 # Munge things so we don't have to hardcode filenames and
7459 # line numbers in our whitelist.
7460 whitelistmsg = "Rule %r defined, but not used"
7461 whitelistargs = args[2:]
7462 else:
7463 whitelistmsg = msg
7464 whitelistargs = args
7465 if (whitelistmsg % whitelistargs) not in SqueakyCleanLogger.errorWhitelist:
7466 self.errors.append(msg % args)
7468 error = warning
7470 def reportGrammarErrors(self):
7471 if self.errors:
7472 raise WebIDLError("\n".join(self.errors), [])
7475 class Parser(Tokenizer):
7476 def getLocation(self, p, i):
7477 return Location(self.lexer, p.lineno(i), p.lexpos(i), self._filename)
7479 def globalScope(self):
7480 return self._globalScope
7482 # The p_Foo functions here must match the WebIDL spec's grammar.
7483 # It's acceptable to split things at '|' boundaries.
7484 def p_Definitions(self, p):
7486 Definitions : ExtendedAttributeList Definition Definitions
7488 if p[2]:
7489 p[0] = [p[2]]
7490 p[2].addExtendedAttributes(p[1])
7491 else:
7492 assert not p[1]
7493 p[0] = []
7495 p[0].extend(p[3])
7497 def p_DefinitionsEmpty(self, p):
7499 Definitions :
7501 p[0] = []
7503 def p_Definition(self, p):
7505 Definition : CallbackOrInterfaceOrMixin
7506 | Namespace
7507 | Partial
7508 | Dictionary
7509 | Exception
7510 | Enum
7511 | Typedef
7512 | IncludesStatement
7514 p[0] = p[1]
7515 assert p[1] # We might not have implemented something ...
7517 def p_CallbackOrInterfaceOrMixinCallback(self, p):
7519 CallbackOrInterfaceOrMixin : CALLBACK CallbackRestOrInterface
7521 if p[2].isInterface():
7522 assert isinstance(p[2], IDLInterface)
7523 p[2].setCallback(True)
7525 p[0] = p[2]
7527 def p_CallbackOrInterfaceOrMixinInterfaceOrMixin(self, p):
7529 CallbackOrInterfaceOrMixin : INTERFACE InterfaceOrMixin
7531 p[0] = p[2]
7533 def p_CallbackRestOrInterface(self, p):
7535 CallbackRestOrInterface : CallbackRest
7536 | CallbackConstructorRest
7537 | CallbackInterface
7539 assert p[1]
7540 p[0] = p[1]
7542 def handleNonPartialObject(
7543 self, location, identifier, constructor, constructorArgs, nonPartialArgs
7546 This handles non-partial objects (interfaces, namespaces and
7547 dictionaries) by checking for an existing partial object, and promoting
7548 it to non-partial as needed. The return value is the non-partial
7549 object.
7551 constructorArgs are all the args for the constructor except the last
7552 one: isKnownNonPartial.
7554 nonPartialArgs are the args for the setNonPartial call.
7556 # The name of the class starts with "IDL", so strip that off.
7557 # Also, starts with a capital letter after that, so nix that
7558 # as well.
7559 prettyname = constructor.__name__[3:].lower()
7561 try:
7562 existingObj = self.globalScope()._lookupIdentifier(identifier)
7563 if existingObj:
7564 if not isinstance(existingObj, constructor):
7565 raise WebIDLError(
7566 "%s has the same name as "
7567 "non-%s object" % (prettyname.capitalize(), prettyname),
7568 [location, existingObj.location],
7570 existingObj.setNonPartial(*nonPartialArgs)
7571 return existingObj
7572 except Exception as ex:
7573 if isinstance(ex, WebIDLError):
7574 raise ex
7575 pass
7577 # True for isKnownNonPartial
7578 return constructor(*(constructorArgs + [True]))
7580 def p_InterfaceOrMixin(self, p):
7582 InterfaceOrMixin : InterfaceRest
7583 | MixinRest
7585 p[0] = p[1]
7587 def p_CallbackInterface(self, p):
7589 CallbackInterface : INTERFACE InterfaceRest
7591 p[0] = p[2]
7593 def p_InterfaceRest(self, p):
7595 InterfaceRest : IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON
7597 location = self.getLocation(p, 1)
7598 identifier = IDLUnresolvedIdentifier(location, p[1])
7599 members = p[4]
7600 parent = p[2]
7602 p[0] = self.handleNonPartialObject(
7603 location,
7604 identifier,
7605 IDLInterface,
7606 [location, self.globalScope(), identifier, parent, members],
7607 [location, parent, members],
7610 def p_InterfaceForwardDecl(self, p):
7612 InterfaceRest : IDENTIFIER SEMICOLON
7614 location = self.getLocation(p, 1)
7615 identifier = IDLUnresolvedIdentifier(location, p[1])
7617 try:
7618 if self.globalScope()._lookupIdentifier(identifier):
7619 p[0] = self.globalScope()._lookupIdentifier(identifier)
7620 if not isinstance(p[0], IDLExternalInterface):
7621 raise WebIDLError(
7622 "Name collision between external "
7623 "interface declaration for identifier "
7624 "%s and %s" % (identifier.name, p[0]),
7625 [location, p[0].location],
7627 return
7628 except Exception as ex:
7629 if isinstance(ex, WebIDLError):
7630 raise ex
7631 pass
7633 p[0] = IDLExternalInterface(location, self.globalScope(), identifier)
7635 def p_MixinRest(self, p):
7637 MixinRest : MIXIN IDENTIFIER LBRACE MixinMembers RBRACE SEMICOLON
7639 location = self.getLocation(p, 1)
7640 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
7641 members = p[4]
7643 p[0] = self.handleNonPartialObject(
7644 location,
7645 identifier,
7646 IDLInterfaceMixin,
7647 [location, self.globalScope(), identifier, members],
7648 [location, members],
7651 def p_Namespace(self, p):
7653 Namespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON
7655 location = self.getLocation(p, 1)
7656 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
7657 members = p[4]
7659 p[0] = self.handleNonPartialObject(
7660 location,
7661 identifier,
7662 IDLNamespace,
7663 [location, self.globalScope(), identifier, members],
7664 [location, None, members],
7667 def p_Partial(self, p):
7669 Partial : PARTIAL PartialDefinition
7671 p[0] = p[2]
7673 def p_PartialDefinitionInterface(self, p):
7675 PartialDefinition : INTERFACE PartialInterfaceOrPartialMixin
7677 p[0] = p[2]
7679 def p_PartialDefinition(self, p):
7681 PartialDefinition : PartialNamespace
7682 | PartialDictionary
7684 p[0] = p[1]
7686 def handlePartialObject(
7687 self,
7688 location,
7689 identifier,
7690 nonPartialConstructor,
7691 nonPartialConstructorArgs,
7692 partialConstructorArgs,
7695 This handles partial objects (interfaces, namespaces and dictionaries)
7696 by checking for an existing non-partial object, and adding ourselves to
7697 it as needed. The return value is our partial object. We use
7698 IDLPartialInterfaceOrNamespace for partial interfaces or namespaces,
7699 and IDLPartialDictionary for partial dictionaries.
7701 nonPartialConstructorArgs are all the args for the non-partial
7702 constructor except the last two: members and isKnownNonPartial.
7704 partialConstructorArgs are the arguments for the partial object
7705 constructor, except the last one (the non-partial object).
7707 # The name of the class starts with "IDL", so strip that off.
7708 # Also, starts with a capital letter after that, so nix that
7709 # as well.
7710 prettyname = nonPartialConstructor.__name__[3:].lower()
7712 nonPartialObject = None
7713 try:
7714 nonPartialObject = self.globalScope()._lookupIdentifier(identifier)
7715 if nonPartialObject:
7716 if not isinstance(nonPartialObject, nonPartialConstructor):
7717 raise WebIDLError(
7718 "Partial %s has the same name as "
7719 "non-%s object" % (prettyname, prettyname),
7720 [location, nonPartialObject.location],
7722 except Exception as ex:
7723 if isinstance(ex, WebIDLError):
7724 raise ex
7725 pass
7727 if not nonPartialObject:
7728 nonPartialObject = nonPartialConstructor(
7729 # No members, False for isKnownNonPartial
7730 *(nonPartialConstructorArgs),
7731 members=[],
7732 isKnownNonPartial=False
7735 partialObject = None
7736 if isinstance(nonPartialObject, IDLDictionary):
7737 partialObject = IDLPartialDictionary(
7738 *(partialConstructorArgs + [nonPartialObject])
7740 elif isinstance(
7741 nonPartialObject, (IDLInterface, IDLInterfaceMixin, IDLNamespace)
7743 partialObject = IDLPartialInterfaceOrNamespace(
7744 *(partialConstructorArgs + [nonPartialObject])
7746 else:
7747 raise WebIDLError(
7748 "Unknown partial object type %s" % type(partialObject), [location]
7751 return partialObject
7753 def p_PartialInterfaceOrPartialMixin(self, p):
7755 PartialInterfaceOrPartialMixin : PartialInterfaceRest
7756 | PartialMixinRest
7758 p[0] = p[1]
7760 def p_PartialInterfaceRest(self, p):
7762 PartialInterfaceRest : IDENTIFIER LBRACE PartialInterfaceMembers RBRACE SEMICOLON
7764 location = self.getLocation(p, 1)
7765 identifier = IDLUnresolvedIdentifier(location, p[1])
7766 members = p[3]
7768 p[0] = self.handlePartialObject(
7769 location,
7770 identifier,
7771 IDLInterface,
7772 [location, self.globalScope(), identifier, None],
7773 [location, identifier, members],
7776 def p_PartialMixinRest(self, p):
7778 PartialMixinRest : MIXIN IDENTIFIER LBRACE MixinMembers RBRACE SEMICOLON
7780 location = self.getLocation(p, 1)
7781 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
7782 members = p[4]
7784 p[0] = self.handlePartialObject(
7785 location,
7786 identifier,
7787 IDLInterfaceMixin,
7788 [location, self.globalScope(), identifier],
7789 [location, identifier, members],
7792 def p_PartialNamespace(self, p):
7794 PartialNamespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON
7796 location = self.getLocation(p, 1)
7797 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
7798 members = p[4]
7800 p[0] = self.handlePartialObject(
7801 location,
7802 identifier,
7803 IDLNamespace,
7804 [location, self.globalScope(), identifier],
7805 [location, identifier, members],
7808 def p_PartialDictionary(self, p):
7810 PartialDictionary : DICTIONARY IDENTIFIER LBRACE DictionaryMembers RBRACE SEMICOLON
7812 location = self.getLocation(p, 1)
7813 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
7814 members = p[4]
7816 p[0] = self.handlePartialObject(
7817 location,
7818 identifier,
7819 IDLDictionary,
7820 [location, self.globalScope(), identifier],
7821 [location, identifier, members],
7824 def p_Inheritance(self, p):
7826 Inheritance : COLON ScopedName
7828 p[0] = IDLIdentifierPlaceholder(self.getLocation(p, 2), p[2])
7830 def p_InheritanceEmpty(self, p):
7832 Inheritance :
7834 pass
7836 def p_InterfaceMembers(self, p):
7838 InterfaceMembers : ExtendedAttributeList InterfaceMember InterfaceMembers
7840 p[0] = [p[2]]
7842 assert not p[1] or p[2]
7843 p[2].addExtendedAttributes(p[1])
7845 p[0].extend(p[3])
7847 def p_InterfaceMembersEmpty(self, p):
7849 InterfaceMembers :
7851 p[0] = []
7853 def p_InterfaceMember(self, p):
7855 InterfaceMember : PartialInterfaceMember
7856 | Constructor
7858 p[0] = p[1]
7860 def p_Constructor(self, p):
7862 Constructor : CONSTRUCTOR LPAREN ArgumentList RPAREN SEMICOLON
7864 p[0] = IDLConstructor(self.getLocation(p, 1), p[3], "constructor")
7866 def p_PartialInterfaceMembers(self, p):
7868 PartialInterfaceMembers : ExtendedAttributeList PartialInterfaceMember PartialInterfaceMembers
7870 p[0] = [p[2]]
7872 assert not p[1] or p[2]
7873 p[2].addExtendedAttributes(p[1])
7875 p[0].extend(p[3])
7877 def p_PartialInterfaceMembersEmpty(self, p):
7879 PartialInterfaceMembers :
7881 p[0] = []
7883 def p_PartialInterfaceMember(self, p):
7885 PartialInterfaceMember : Const
7886 | AttributeOrOperationOrMaplikeOrSetlikeOrIterable
7888 p[0] = p[1]
7890 def p_MixinMembersEmpty(self, p):
7892 MixinMembers :
7894 p[0] = []
7896 def p_MixinMembers(self, p):
7898 MixinMembers : ExtendedAttributeList MixinMember MixinMembers
7900 p[0] = [p[2]]
7902 assert not p[1] or p[2]
7903 p[2].addExtendedAttributes(p[1])
7905 p[0].extend(p[3])
7907 def p_MixinMember(self, p):
7909 MixinMember : Const
7910 | Attribute
7911 | Operation
7913 p[0] = p[1]
7915 def p_Dictionary(self, p):
7917 Dictionary : DICTIONARY IDENTIFIER Inheritance LBRACE DictionaryMembers RBRACE SEMICOLON
7919 location = self.getLocation(p, 1)
7920 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
7921 members = p[5]
7922 p[0] = IDLDictionary(location, self.globalScope(), identifier, p[3], members)
7924 def p_DictionaryMembers(self, p):
7926 DictionaryMembers : ExtendedAttributeList DictionaryMember DictionaryMembers
7929 if len(p) == 1:
7930 # We're at the end of the list
7931 p[0] = []
7932 return
7933 p[2].addExtendedAttributes(p[1])
7934 p[0] = [p[2]]
7935 p[0].extend(p[3])
7937 def p_DictionaryMemberRequired(self, p):
7939 DictionaryMember : REQUIRED TypeWithExtendedAttributes IDENTIFIER SEMICOLON
7941 # These quack a lot like required arguments, so just treat them that way.
7942 t = p[2]
7943 assert isinstance(t, IDLType)
7944 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3])
7946 p[0] = IDLArgument(
7947 self.getLocation(p, 3),
7948 identifier,
7950 optional=False,
7951 defaultValue=None,
7952 variadic=False,
7953 dictionaryMember=True,
7956 def p_DictionaryMember(self, p):
7958 DictionaryMember : Type IDENTIFIER Default SEMICOLON
7960 # These quack a lot like optional arguments, so just treat them that way.
7961 t = p[1]
7962 assert isinstance(t, IDLType)
7963 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
7964 defaultValue = p[3]
7966 # Any attributes that precede this may apply to the type, so
7967 # we configure the argument to forward type attributes down instead of producing
7968 # a parse error
7969 p[0] = IDLArgument(
7970 self.getLocation(p, 2),
7971 identifier,
7973 optional=True,
7974 defaultValue=defaultValue,
7975 variadic=False,
7976 dictionaryMember=True,
7977 allowTypeAttributes=True,
7980 def p_Default(self, p):
7982 Default : EQUALS DefaultValue
7985 if len(p) > 1:
7986 p[0] = p[2]
7987 else:
7988 p[0] = None
7990 def p_DefaultValue(self, p):
7992 DefaultValue : ConstValue
7993 | LBRACKET RBRACKET
7994 | LBRACE RBRACE
7996 if len(p) == 2:
7997 p[0] = p[1]
7998 else:
7999 assert len(p) == 3 # Must be [] or {}
8000 if p[1] == "[":
8001 p[0] = IDLEmptySequenceValue(self.getLocation(p, 1))
8002 else:
8003 assert p[1] == "{"
8004 p[0] = IDLDefaultDictionaryValue(self.getLocation(p, 1))
8006 def p_DefaultValueNull(self, p):
8008 DefaultValue : NULL
8010 p[0] = IDLNullValue(self.getLocation(p, 1))
8012 def p_DefaultValueUndefined(self, p):
8014 DefaultValue : UNDEFINED
8016 p[0] = IDLUndefinedValue(self.getLocation(p, 1))
8018 def p_Exception(self, p):
8020 Exception : EXCEPTION IDENTIFIER Inheritance LBRACE ExceptionMembers RBRACE SEMICOLON
8022 pass
8024 def p_Enum(self, p):
8026 Enum : ENUM IDENTIFIER LBRACE EnumValueList RBRACE SEMICOLON
8028 location = self.getLocation(p, 1)
8029 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
8031 values = p[4]
8032 assert values
8033 p[0] = IDLEnum(location, self.globalScope(), identifier, values)
8035 def p_EnumValueList(self, p):
8037 EnumValueList : STRING EnumValueListComma
8039 p[0] = [p[1]]
8040 p[0].extend(p[2])
8042 def p_EnumValueListComma(self, p):
8044 EnumValueListComma : COMMA EnumValueListString
8046 p[0] = p[2]
8048 def p_EnumValueListCommaEmpty(self, p):
8050 EnumValueListComma :
8052 p[0] = []
8054 def p_EnumValueListString(self, p):
8056 EnumValueListString : STRING EnumValueListComma
8058 p[0] = [p[1]]
8059 p[0].extend(p[2])
8061 def p_EnumValueListStringEmpty(self, p):
8063 EnumValueListString :
8065 p[0] = []
8067 def p_CallbackRest(self, p):
8069 CallbackRest : IDENTIFIER EQUALS Type LPAREN ArgumentList RPAREN SEMICOLON
8071 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1])
8072 p[0] = IDLCallback(
8073 self.getLocation(p, 1),
8074 self.globalScope(),
8075 identifier,
8076 p[3],
8077 p[5],
8078 isConstructor=False,
8081 def p_CallbackConstructorRest(self, p):
8083 CallbackConstructorRest : CONSTRUCTOR IDENTIFIER EQUALS Type LPAREN ArgumentList RPAREN SEMICOLON
8085 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
8086 p[0] = IDLCallback(
8087 self.getLocation(p, 2),
8088 self.globalScope(),
8089 identifier,
8090 p[4],
8091 p[6],
8092 isConstructor=True,
8095 def p_ExceptionMembers(self, p):
8097 ExceptionMembers : ExtendedAttributeList ExceptionMember ExceptionMembers
8100 pass
8102 def p_Typedef(self, p):
8104 Typedef : TYPEDEF TypeWithExtendedAttributes IDENTIFIER SEMICOLON
8106 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3])
8107 typedef = IDLTypedef(
8108 self.getLocation(p, 1),
8109 self.globalScope(),
8110 p[2],
8111 identifier,
8113 p[0] = typedef
8115 def p_IncludesStatement(self, p):
8117 IncludesStatement : ScopedName INCLUDES ScopedName SEMICOLON
8119 assert p[2] == "includes"
8120 interface = IDLIdentifierPlaceholder(self.getLocation(p, 1), p[1])
8121 mixin = IDLIdentifierPlaceholder(self.getLocation(p, 3), p[3])
8122 p[0] = IDLIncludesStatement(self.getLocation(p, 1), interface, mixin)
8124 def p_Const(self, p):
8126 Const : CONST ConstType IDENTIFIER EQUALS ConstValue SEMICOLON
8128 location = self.getLocation(p, 1)
8129 type = p[2]
8130 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3])
8131 value = p[5]
8132 p[0] = IDLConst(location, identifier, type, value)
8134 def p_ConstValueBoolean(self, p):
8136 ConstValue : BooleanLiteral
8138 location = self.getLocation(p, 1)
8139 booleanType = BuiltinTypes[IDLBuiltinType.Types.boolean]
8140 p[0] = IDLValue(location, booleanType, p[1])
8142 def p_ConstValueInteger(self, p):
8144 ConstValue : INTEGER
8146 location = self.getLocation(p, 1)
8148 # We don't know ahead of time what type the integer literal is.
8149 # Determine the smallest type it could possibly fit in and use that.
8150 integerType = matchIntegerValueToType(p[1])
8151 if integerType is None:
8152 raise WebIDLError("Integer literal out of range", [location])
8154 p[0] = IDLValue(location, integerType, p[1])
8156 def p_ConstValueFloat(self, p):
8158 ConstValue : FLOATLITERAL
8160 location = self.getLocation(p, 1)
8161 p[0] = IDLValue(
8162 location, BuiltinTypes[IDLBuiltinType.Types.unrestricted_float], p[1]
8165 def p_ConstValueString(self, p):
8167 ConstValue : STRING
8169 location = self.getLocation(p, 1)
8170 stringType = BuiltinTypes[IDLBuiltinType.Types.domstring]
8171 p[0] = IDLValue(location, stringType, p[1])
8173 def p_BooleanLiteralTrue(self, p):
8175 BooleanLiteral : TRUE
8177 p[0] = True
8179 def p_BooleanLiteralFalse(self, p):
8181 BooleanLiteral : FALSE
8183 p[0] = False
8185 def p_AttributeOrOperationOrMaplikeOrSetlikeOrIterable(self, p):
8187 AttributeOrOperationOrMaplikeOrSetlikeOrIterable : Attribute
8188 | Maplike
8189 | Setlike
8190 | Iterable
8191 | AsyncIterable
8192 | Operation
8194 p[0] = p[1]
8196 def p_Iterable(self, p):
8198 Iterable : ITERABLE LT TypeWithExtendedAttributes GT SEMICOLON
8199 | ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON
8201 location = self.getLocation(p, 1)
8202 identifier = IDLUnresolvedIdentifier(
8203 location, "__iterable", allowDoubleUnderscore=True
8205 if len(p) > 6:
8206 keyType = p[3]
8207 valueType = p[5]
8208 else:
8209 keyType = None
8210 valueType = p[3]
8212 p[0] = IDLIterable(location, identifier, keyType, valueType, self.globalScope())
8214 def p_AsyncIterable(self, p):
8216 AsyncIterable : ASYNC ITERABLE LT TypeWithExtendedAttributes GT SEMICOLON
8217 | ASYNC ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON
8218 | ASYNC ITERABLE LT TypeWithExtendedAttributes GT LPAREN ArgumentList RPAREN SEMICOLON
8219 | ASYNC ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT LPAREN ArgumentList RPAREN SEMICOLON
8221 location = self.getLocation(p, 2)
8222 identifier = IDLUnresolvedIdentifier(
8223 location, "__iterable", allowDoubleUnderscore=True
8225 if len(p) == 12:
8226 keyType = p[4]
8227 valueType = p[6]
8228 argList = p[9]
8229 elif len(p) == 10:
8230 keyType = None
8231 valueType = p[4]
8232 argList = p[7]
8233 elif len(p) == 9:
8234 keyType = p[4]
8235 valueType = p[6]
8236 argList = []
8237 else:
8238 keyType = None
8239 valueType = p[4]
8240 argList = []
8242 p[0] = IDLAsyncIterable(
8243 location, identifier, keyType, valueType, argList, self.globalScope()
8246 def p_Setlike(self, p):
8248 Setlike : ReadOnly SETLIKE LT TypeWithExtendedAttributes GT SEMICOLON
8250 readonly = p[1]
8251 maplikeOrSetlikeType = p[2]
8252 location = self.getLocation(p, 2)
8253 identifier = IDLUnresolvedIdentifier(
8254 location, "__setlike", allowDoubleUnderscore=True
8256 keyType = p[4]
8257 valueType = keyType
8258 p[0] = IDLMaplikeOrSetlike(
8259 location, identifier, maplikeOrSetlikeType, readonly, keyType, valueType
8262 def p_Maplike(self, p):
8264 Maplike : ReadOnly MAPLIKE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON
8266 readonly = p[1]
8267 maplikeOrSetlikeType = p[2]
8268 location = self.getLocation(p, 2)
8269 identifier = IDLUnresolvedIdentifier(
8270 location, "__maplike", allowDoubleUnderscore=True
8272 keyType = p[4]
8273 valueType = p[6]
8274 p[0] = IDLMaplikeOrSetlike(
8275 location, identifier, maplikeOrSetlikeType, readonly, keyType, valueType
8278 def p_AttributeWithQualifier(self, p):
8280 Attribute : Qualifier AttributeRest
8282 static = IDLInterfaceMember.Special.Static in p[1]
8283 stringifier = IDLInterfaceMember.Special.Stringifier in p[1]
8284 (location, identifier, type, readonly) = p[2]
8285 p[0] = IDLAttribute(
8286 location, identifier, type, readonly, static=static, stringifier=stringifier
8289 def p_AttributeInherited(self, p):
8291 Attribute : INHERIT AttributeRest
8293 (location, identifier, type, readonly) = p[2]
8294 p[0] = IDLAttribute(location, identifier, type, readonly, inherit=True)
8296 def p_Attribute(self, p):
8298 Attribute : AttributeRest
8300 (location, identifier, type, readonly) = p[1]
8301 p[0] = IDLAttribute(location, identifier, type, readonly, inherit=False)
8303 def p_AttributeRest(self, p):
8305 AttributeRest : ReadOnly ATTRIBUTE TypeWithExtendedAttributes AttributeName SEMICOLON
8307 location = self.getLocation(p, 2)
8308 readonly = p[1]
8309 t = p[3]
8310 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 4), p[4])
8311 p[0] = (location, identifier, t, readonly)
8313 def p_ReadOnly(self, p):
8315 ReadOnly : READONLY
8317 p[0] = True
8319 def p_ReadOnlyEmpty(self, p):
8321 ReadOnly :
8323 p[0] = False
8325 def p_Operation(self, p):
8327 Operation : Qualifiers OperationRest
8329 qualifiers = p[1]
8331 # Disallow duplicates in the qualifier set
8332 if not len(set(qualifiers)) == len(qualifiers):
8333 raise WebIDLError(
8334 "Duplicate qualifiers are not allowed", [self.getLocation(p, 1)]
8337 static = IDLInterfaceMember.Special.Static in p[1]
8338 # If static is there that's all that's allowed. This is disallowed
8339 # by the parser, so we can assert here.
8340 assert not static or len(qualifiers) == 1
8342 stringifier = IDLInterfaceMember.Special.Stringifier in p[1]
8343 # If stringifier is there that's all that's allowed. This is disallowed
8344 # by the parser, so we can assert here.
8345 assert not stringifier or len(qualifiers) == 1
8347 getter = True if IDLMethod.Special.Getter in p[1] else False
8348 setter = True if IDLMethod.Special.Setter in p[1] else False
8349 deleter = True if IDLMethod.Special.Deleter in p[1] else False
8350 legacycaller = True if IDLMethod.Special.LegacyCaller in p[1] else False
8352 if getter or deleter:
8353 if setter:
8354 raise WebIDLError(
8355 "getter and deleter are incompatible with setter",
8356 [self.getLocation(p, 1)],
8359 (returnType, identifier, arguments) = p[2]
8361 assert isinstance(returnType, IDLType)
8363 specialType = IDLMethod.NamedOrIndexed.Neither
8365 if getter or deleter:
8366 if len(arguments) != 1:
8367 raise WebIDLError(
8368 "%s has wrong number of arguments"
8369 % ("getter" if getter else "deleter"),
8370 [self.getLocation(p, 2)],
8372 argType = arguments[0].type
8373 if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]:
8374 specialType = IDLMethod.NamedOrIndexed.Named
8375 elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]:
8376 specialType = IDLMethod.NamedOrIndexed.Indexed
8377 if deleter:
8378 raise WebIDLError(
8379 "There is no such thing as an indexed deleter.",
8380 [self.getLocation(p, 1)],
8382 else:
8383 raise WebIDLError(
8384 "%s has wrong argument type (must be DOMString or UnsignedLong)"
8385 % ("getter" if getter else "deleter"),
8386 [arguments[0].location],
8388 if arguments[0].optional or arguments[0].variadic:
8389 raise WebIDLError(
8390 "%s cannot have %s argument"
8392 "getter" if getter else "deleter",
8393 "optional" if arguments[0].optional else "variadic",
8395 [arguments[0].location],
8397 if getter:
8398 if returnType.isUndefined():
8399 raise WebIDLError(
8400 "getter cannot have undefined return type", [self.getLocation(p, 2)]
8402 if setter:
8403 if len(arguments) != 2:
8404 raise WebIDLError(
8405 "setter has wrong number of arguments", [self.getLocation(p, 2)]
8407 argType = arguments[0].type
8408 if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]:
8409 specialType = IDLMethod.NamedOrIndexed.Named
8410 elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]:
8411 specialType = IDLMethod.NamedOrIndexed.Indexed
8412 else:
8413 raise WebIDLError(
8414 "settter has wrong argument type (must be DOMString or UnsignedLong)",
8415 [arguments[0].location],
8417 if arguments[0].optional or arguments[0].variadic:
8418 raise WebIDLError(
8419 "setter cannot have %s argument"
8420 % ("optional" if arguments[0].optional else "variadic"),
8421 [arguments[0].location],
8423 if arguments[1].optional or arguments[1].variadic:
8424 raise WebIDLError(
8425 "setter cannot have %s argument"
8426 % ("optional" if arguments[1].optional else "variadic"),
8427 [arguments[1].location],
8430 if stringifier:
8431 if len(arguments) != 0:
8432 raise WebIDLError(
8433 "stringifier has wrong number of arguments",
8434 [self.getLocation(p, 2)],
8436 if not returnType.isDOMString():
8437 raise WebIDLError(
8438 "stringifier must have DOMString return type",
8439 [self.getLocation(p, 2)],
8442 # identifier might be None. This is only permitted for special methods.
8443 if not identifier:
8444 if (
8445 not getter
8446 and not setter
8447 and not deleter
8448 and not legacycaller
8449 and not stringifier
8451 raise WebIDLError(
8452 "Identifier required for non-special methods",
8453 [self.getLocation(p, 2)],
8456 location = BuiltinLocation("<auto-generated-identifier>")
8457 identifier = IDLUnresolvedIdentifier(
8458 location,
8459 "__%s%s%s%s%s%s"
8462 "named"
8463 if specialType == IDLMethod.NamedOrIndexed.Named
8464 else (
8465 "indexed"
8466 if specialType == IDLMethod.NamedOrIndexed.Indexed
8467 else ""
8470 "getter" if getter else "",
8471 "setter" if setter else "",
8472 "deleter" if deleter else "",
8473 "legacycaller" if legacycaller else "",
8474 "stringifier" if stringifier else "",
8476 allowDoubleUnderscore=True,
8479 method = IDLMethod(
8480 self.getLocation(p, 2),
8481 identifier,
8482 returnType,
8483 arguments,
8484 static=static,
8485 getter=getter,
8486 setter=setter,
8487 deleter=deleter,
8488 specialType=specialType,
8489 legacycaller=legacycaller,
8490 stringifier=stringifier,
8492 p[0] = method
8494 def p_Stringifier(self, p):
8496 Operation : STRINGIFIER SEMICOLON
8498 identifier = IDLUnresolvedIdentifier(
8499 BuiltinLocation("<auto-generated-identifier>"),
8500 "__stringifier",
8501 allowDoubleUnderscore=True,
8503 method = IDLMethod(
8504 self.getLocation(p, 1),
8505 identifier,
8506 returnType=BuiltinTypes[IDLBuiltinType.Types.domstring],
8507 arguments=[],
8508 stringifier=True,
8510 p[0] = method
8512 def p_QualifierStatic(self, p):
8514 Qualifier : STATIC
8516 p[0] = [IDLInterfaceMember.Special.Static]
8518 def p_QualifierStringifier(self, p):
8520 Qualifier : STRINGIFIER
8522 p[0] = [IDLInterfaceMember.Special.Stringifier]
8524 def p_Qualifiers(self, p):
8526 Qualifiers : Qualifier
8527 | Specials
8529 p[0] = p[1]
8531 def p_Specials(self, p):
8533 Specials : Special Specials
8535 p[0] = [p[1]]
8536 p[0].extend(p[2])
8538 def p_SpecialsEmpty(self, p):
8540 Specials :
8542 p[0] = []
8544 def p_SpecialGetter(self, p):
8546 Special : GETTER
8548 p[0] = IDLMethod.Special.Getter
8550 def p_SpecialSetter(self, p):
8552 Special : SETTER
8554 p[0] = IDLMethod.Special.Setter
8556 def p_SpecialDeleter(self, p):
8558 Special : DELETER
8560 p[0] = IDLMethod.Special.Deleter
8562 def p_SpecialLegacyCaller(self, p):
8564 Special : LEGACYCALLER
8566 p[0] = IDLMethod.Special.LegacyCaller
8568 def p_OperationRest(self, p):
8570 OperationRest : Type OptionalIdentifier LPAREN ArgumentList RPAREN SEMICOLON
8572 p[0] = (p[1], p[2], p[4])
8574 def p_OptionalIdentifier(self, p):
8576 OptionalIdentifier : IDENTIFIER
8578 p[0] = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1])
8580 def p_OptionalIdentifierEmpty(self, p):
8582 OptionalIdentifier :
8584 pass
8586 def p_ArgumentList(self, p):
8588 ArgumentList : Argument Arguments
8590 p[0] = [p[1]] if p[1] else []
8591 p[0].extend(p[2])
8593 def p_ArgumentListEmpty(self, p):
8595 ArgumentList :
8597 p[0] = []
8599 def p_Arguments(self, p):
8601 Arguments : COMMA Argument Arguments
8603 p[0] = [p[2]] if p[2] else []
8604 p[0].extend(p[3])
8606 def p_ArgumentsEmpty(self, p):
8608 Arguments :
8610 p[0] = []
8612 def p_Argument(self, p):
8614 Argument : ExtendedAttributeList ArgumentRest
8616 p[0] = p[2]
8617 p[0].addExtendedAttributes(p[1])
8619 def p_ArgumentRestOptional(self, p):
8621 ArgumentRest : OPTIONAL TypeWithExtendedAttributes ArgumentName Default
8623 t = p[2]
8624 assert isinstance(t, IDLType)
8625 # Arg names can be reserved identifiers
8626 identifier = IDLUnresolvedIdentifier(
8627 self.getLocation(p, 3), p[3], allowForbidden=True
8630 defaultValue = p[4]
8632 # We can't test t.isAny() here and give it a default value as needed,
8633 # since at this point t is not a fully resolved type yet (e.g. it might
8634 # be a typedef). We'll handle the 'any' case in IDLArgument.complete.
8636 p[0] = IDLArgument(
8637 self.getLocation(p, 3), identifier, t, True, defaultValue, False
8640 def p_ArgumentRest(self, p):
8642 ArgumentRest : Type Ellipsis ArgumentName
8644 t = p[1]
8645 assert isinstance(t, IDLType)
8646 # Arg names can be reserved identifiers
8647 identifier = IDLUnresolvedIdentifier(
8648 self.getLocation(p, 3), p[3], allowForbidden=True
8651 variadic = p[2]
8653 # We can't test t.isAny() here and give it a default value as needed,
8654 # since at this point t is not a fully resolved type yet (e.g. it might
8655 # be a typedef). We'll handle the 'any' case in IDLArgument.complete.
8657 # variadic implies optional
8658 # Any attributes that precede this may apply to the type, so
8659 # we configure the argument to forward type attributes down instead of producing
8660 # a parse error
8661 p[0] = IDLArgument(
8662 self.getLocation(p, 3),
8663 identifier,
8665 variadic,
8666 None,
8667 variadic,
8668 allowTypeAttributes=True,
8671 def p_ArgumentName(self, p):
8673 ArgumentName : IDENTIFIER
8674 | ArgumentNameKeyword
8676 p[0] = p[1]
8678 def p_ArgumentNameKeyword(self, p):
8680 ArgumentNameKeyword : ASYNC
8681 | ATTRIBUTE
8682 | CALLBACK
8683 | CONST
8684 | CONSTRUCTOR
8685 | DELETER
8686 | DICTIONARY
8687 | ENUM
8688 | EXCEPTION
8689 | GETTER
8690 | INCLUDES
8691 | INHERIT
8692 | INTERFACE
8693 | ITERABLE
8694 | LEGACYCALLER
8695 | MAPLIKE
8696 | MIXIN
8697 | NAMESPACE
8698 | PARTIAL
8699 | READONLY
8700 | REQUIRED
8701 | SERIALIZER
8702 | SETLIKE
8703 | SETTER
8704 | STATIC
8705 | STRINGIFIER
8706 | TYPEDEF
8707 | UNRESTRICTED
8709 p[0] = p[1]
8711 def p_AttributeName(self, p):
8713 AttributeName : IDENTIFIER
8714 | AttributeNameKeyword
8716 p[0] = p[1]
8718 def p_AttributeNameKeyword(self, p):
8720 AttributeNameKeyword : ASYNC
8721 | REQUIRED
8723 p[0] = p[1]
8725 def p_Ellipsis(self, p):
8727 Ellipsis : ELLIPSIS
8729 p[0] = True
8731 def p_EllipsisEmpty(self, p):
8733 Ellipsis :
8735 p[0] = False
8737 def p_ExceptionMember(self, p):
8739 ExceptionMember : Const
8740 | ExceptionField
8742 pass
8744 def p_ExceptionField(self, p):
8746 ExceptionField : Type IDENTIFIER SEMICOLON
8748 pass
8750 def p_ExtendedAttributeList(self, p):
8752 ExtendedAttributeList : LBRACKET ExtendedAttribute ExtendedAttributes RBRACKET
8754 p[0] = [p[2]]
8755 if p[3]:
8756 p[0].extend(p[3])
8758 def p_ExtendedAttributeListEmpty(self, p):
8760 ExtendedAttributeList :
8762 p[0] = []
8764 def p_ExtendedAttribute(self, p):
8766 ExtendedAttribute : ExtendedAttributeNoArgs
8767 | ExtendedAttributeArgList
8768 | ExtendedAttributeIdent
8769 | ExtendedAttributeWildcard
8770 | ExtendedAttributeNamedArgList
8771 | ExtendedAttributeIdentList
8773 p[0] = IDLExtendedAttribute(self.getLocation(p, 1), p[1])
8775 def p_ExtendedAttributeEmpty(self, p):
8777 ExtendedAttribute :
8779 pass
8781 def p_ExtendedAttributes(self, p):
8783 ExtendedAttributes : COMMA ExtendedAttribute ExtendedAttributes
8785 p[0] = [p[2]] if p[2] else []
8786 p[0].extend(p[3])
8788 def p_ExtendedAttributesEmpty(self, p):
8790 ExtendedAttributes :
8792 p[0] = []
8794 def p_Other(self, p):
8796 Other : INTEGER
8797 | FLOATLITERAL
8798 | IDENTIFIER
8799 | STRING
8800 | OTHER
8801 | ELLIPSIS
8802 | COLON
8803 | SCOPE
8804 | SEMICOLON
8805 | LT
8806 | EQUALS
8807 | GT
8808 | QUESTIONMARK
8809 | ASTERISK
8810 | DOMSTRING
8811 | BYTESTRING
8812 | USVSTRING
8813 | UTF8STRING
8814 | JSSTRING
8815 | PROMISE
8816 | ANY
8817 | BOOLEAN
8818 | BYTE
8819 | DOUBLE
8820 | FALSE
8821 | FLOAT
8822 | LONG
8823 | NULL
8824 | OBJECT
8825 | OCTET
8826 | OR
8827 | OPTIONAL
8828 | RECORD
8829 | SEQUENCE
8830 | SHORT
8831 | SYMBOL
8832 | TRUE
8833 | UNSIGNED
8834 | UNDEFINED
8835 | ArgumentNameKeyword
8837 pass
8839 def p_OtherOrComma(self, p):
8841 OtherOrComma : Other
8842 | COMMA
8844 pass
8846 def p_TypeSingleType(self, p):
8848 Type : SingleType
8850 p[0] = p[1]
8852 def p_TypeUnionType(self, p):
8854 Type : UnionType Null
8856 p[0] = self.handleNullable(p[1], p[2])
8858 def p_TypeWithExtendedAttributes(self, p):
8860 TypeWithExtendedAttributes : ExtendedAttributeList Type
8862 p[0] = p[2].withExtendedAttributes(p[1])
8864 def p_SingleTypeDistinguishableType(self, p):
8866 SingleType : DistinguishableType
8868 p[0] = p[1]
8870 def p_SingleTypeAnyType(self, p):
8872 SingleType : ANY
8874 p[0] = BuiltinTypes[IDLBuiltinType.Types.any]
8876 def p_SingleTypePromiseType(self, p):
8878 SingleType : PROMISE LT Type GT
8880 p[0] = IDLPromiseType(self.getLocation(p, 1), p[3])
8882 def p_UnionType(self, p):
8884 UnionType : LPAREN UnionMemberType OR UnionMemberType UnionMemberTypes RPAREN
8886 types = [p[2], p[4]]
8887 types.extend(p[5])
8888 p[0] = IDLUnionType(self.getLocation(p, 1), types)
8890 def p_UnionMemberTypeDistinguishableType(self, p):
8892 UnionMemberType : ExtendedAttributeList DistinguishableType
8894 p[0] = p[2].withExtendedAttributes(p[1])
8896 def p_UnionMemberType(self, p):
8898 UnionMemberType : UnionType Null
8900 p[0] = self.handleNullable(p[1], p[2])
8902 def p_UnionMemberTypes(self, p):
8904 UnionMemberTypes : OR UnionMemberType UnionMemberTypes
8906 p[0] = [p[2]]
8907 p[0].extend(p[3])
8909 def p_UnionMemberTypesEmpty(self, p):
8911 UnionMemberTypes :
8913 p[0] = []
8915 def p_DistinguishableType(self, p):
8917 DistinguishableType : PrimitiveType Null
8918 | ARRAYBUFFER Null
8919 | OBJECT Null
8920 | UNDEFINED Null
8922 if p[1] == "object":
8923 type = BuiltinTypes[IDLBuiltinType.Types.object]
8924 elif p[1] == "ArrayBuffer":
8925 type = BuiltinTypes[IDLBuiltinType.Types.ArrayBuffer]
8926 elif p[1] == "undefined":
8927 type = BuiltinTypes[IDLBuiltinType.Types.undefined]
8928 else:
8929 type = BuiltinTypes[p[1]]
8931 p[0] = self.handleNullable(type, p[2])
8933 def p_DistinguishableTypeStringType(self, p):
8935 DistinguishableType : StringType Null
8937 p[0] = self.handleNullable(p[1], p[2])
8939 def p_DistinguishableTypeSequenceType(self, p):
8941 DistinguishableType : SEQUENCE LT TypeWithExtendedAttributes GT Null
8943 innerType = p[3]
8944 type = IDLSequenceType(self.getLocation(p, 1), innerType)
8945 p[0] = self.handleNullable(type, p[5])
8947 def p_DistinguishableTypeRecordType(self, p):
8949 DistinguishableType : RECORD LT StringType COMMA TypeWithExtendedAttributes GT Null
8951 keyType = p[3]
8952 valueType = p[5]
8953 type = IDLRecordType(self.getLocation(p, 1), keyType, valueType)
8954 p[0] = self.handleNullable(type, p[7])
8956 def p_DistinguishableTypeObservableArrayType(self, p):
8958 DistinguishableType : OBSERVABLEARRAY LT TypeWithExtendedAttributes GT Null
8960 innerType = p[3]
8961 type = IDLObservableArrayType(self.getLocation(p, 1), innerType)
8962 p[0] = self.handleNullable(type, p[5])
8964 def p_DistinguishableTypeScopedName(self, p):
8966 DistinguishableType : ScopedName Null
8968 assert isinstance(p[1], IDLUnresolvedIdentifier)
8970 if p[1].name == "Promise":
8971 raise WebIDLError(
8972 "Promise used without saying what it's parametrized over",
8973 [self.getLocation(p, 1)],
8976 type = None
8978 try:
8979 if self.globalScope()._lookupIdentifier(p[1]):
8980 obj = self.globalScope()._lookupIdentifier(p[1])
8981 assert not obj.isType()
8982 if obj.isTypedef():
8983 type = IDLTypedefType(
8984 self.getLocation(p, 1), obj.innerType, obj.identifier.name
8986 elif obj.isCallback() and not obj.isInterface():
8987 type = IDLCallbackType(self.getLocation(p, 1), obj)
8988 else:
8989 type = IDLWrapperType(self.getLocation(p, 1), p[1])
8990 p[0] = self.handleNullable(type, p[2])
8991 return
8992 except Exception:
8993 pass
8995 type = IDLUnresolvedType(self.getLocation(p, 1), p[1])
8996 p[0] = self.handleNullable(type, p[2])
8998 def p_ConstType(self, p):
9000 ConstType : PrimitiveType
9002 p[0] = BuiltinTypes[p[1]]
9004 def p_ConstTypeIdentifier(self, p):
9006 ConstType : IDENTIFIER
9008 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1])
9010 p[0] = IDLUnresolvedType(self.getLocation(p, 1), identifier)
9012 def p_PrimitiveTypeUint(self, p):
9014 PrimitiveType : UnsignedIntegerType
9016 p[0] = p[1]
9018 def p_PrimitiveTypeBoolean(self, p):
9020 PrimitiveType : BOOLEAN
9022 p[0] = IDLBuiltinType.Types.boolean
9024 def p_PrimitiveTypeByte(self, p):
9026 PrimitiveType : BYTE
9028 p[0] = IDLBuiltinType.Types.byte
9030 def p_PrimitiveTypeOctet(self, p):
9032 PrimitiveType : OCTET
9034 p[0] = IDLBuiltinType.Types.octet
9036 def p_PrimitiveTypeFloat(self, p):
9038 PrimitiveType : FLOAT
9040 p[0] = IDLBuiltinType.Types.float
9042 def p_PrimitiveTypeUnrestictedFloat(self, p):
9044 PrimitiveType : UNRESTRICTED FLOAT
9046 p[0] = IDLBuiltinType.Types.unrestricted_float
9048 def p_PrimitiveTypeDouble(self, p):
9050 PrimitiveType : DOUBLE
9052 p[0] = IDLBuiltinType.Types.double
9054 def p_PrimitiveTypeUnrestictedDouble(self, p):
9056 PrimitiveType : UNRESTRICTED DOUBLE
9058 p[0] = IDLBuiltinType.Types.unrestricted_double
9060 def p_StringType(self, p):
9062 StringType : BuiltinStringType
9064 p[0] = BuiltinTypes[p[1]]
9066 def p_BuiltinStringTypeDOMString(self, p):
9068 BuiltinStringType : DOMSTRING
9070 p[0] = IDLBuiltinType.Types.domstring
9072 def p_BuiltinStringTypeBytestring(self, p):
9074 BuiltinStringType : BYTESTRING
9076 p[0] = IDLBuiltinType.Types.bytestring
9078 def p_BuiltinStringTypeUSVString(self, p):
9080 BuiltinStringType : USVSTRING
9082 p[0] = IDLBuiltinType.Types.usvstring
9084 def p_BuiltinStringTypeUTF8String(self, p):
9086 BuiltinStringType : UTF8STRING
9088 p[0] = IDLBuiltinType.Types.utf8string
9090 def p_BuiltinStringTypeJSString(self, p):
9092 BuiltinStringType : JSSTRING
9094 p[0] = IDLBuiltinType.Types.jsstring
9096 def p_UnsignedIntegerTypeUnsigned(self, p):
9098 UnsignedIntegerType : UNSIGNED IntegerType
9100 # Adding one to a given signed integer type gets you the unsigned type:
9101 p[0] = p[2] + 1
9103 def p_UnsignedIntegerType(self, p):
9105 UnsignedIntegerType : IntegerType
9107 p[0] = p[1]
9109 def p_IntegerTypeShort(self, p):
9111 IntegerType : SHORT
9113 p[0] = IDLBuiltinType.Types.short
9115 def p_IntegerTypeLong(self, p):
9117 IntegerType : LONG OptionalLong
9119 if p[2]:
9120 p[0] = IDLBuiltinType.Types.long_long
9121 else:
9122 p[0] = IDLBuiltinType.Types.long
9124 def p_OptionalLong(self, p):
9126 OptionalLong : LONG
9128 p[0] = True
9130 def p_OptionalLongEmpty(self, p):
9132 OptionalLong :
9134 p[0] = False
9136 def p_Null(self, p):
9138 Null : QUESTIONMARK
9141 if len(p) > 1:
9142 p[0] = self.getLocation(p, 1)
9143 else:
9144 p[0] = None
9146 def p_ScopedName(self, p):
9148 ScopedName : AbsoluteScopedName
9149 | RelativeScopedName
9151 p[0] = p[1]
9153 def p_AbsoluteScopedName(self, p):
9155 AbsoluteScopedName : SCOPE IDENTIFIER ScopedNameParts
9157 assert False
9158 pass
9160 def p_RelativeScopedName(self, p):
9162 RelativeScopedName : IDENTIFIER ScopedNameParts
9164 assert not p[2] # Not implemented!
9166 p[0] = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1])
9168 def p_ScopedNameParts(self, p):
9170 ScopedNameParts : SCOPE IDENTIFIER ScopedNameParts
9172 assert False
9173 pass
9175 def p_ScopedNamePartsEmpty(self, p):
9177 ScopedNameParts :
9179 p[0] = None
9181 def p_ExtendedAttributeNoArgs(self, p):
9183 ExtendedAttributeNoArgs : IDENTIFIER
9185 p[0] = (p[1],)
9187 def p_ExtendedAttributeArgList(self, p):
9189 ExtendedAttributeArgList : IDENTIFIER LPAREN ArgumentList RPAREN
9191 p[0] = (p[1], p[3])
9193 def p_ExtendedAttributeIdent(self, p):
9195 ExtendedAttributeIdent : IDENTIFIER EQUALS STRING
9196 | IDENTIFIER EQUALS IDENTIFIER
9198 p[0] = (p[1], p[3])
9200 def p_ExtendedAttributeWildcard(self, p):
9202 ExtendedAttributeWildcard : IDENTIFIER EQUALS ASTERISK
9204 p[0] = (p[1], p[3])
9206 def p_ExtendedAttributeNamedArgList(self, p):
9208 ExtendedAttributeNamedArgList : IDENTIFIER EQUALS IDENTIFIER LPAREN ArgumentList RPAREN
9210 p[0] = (p[1], p[3], p[5])
9212 def p_ExtendedAttributeIdentList(self, p):
9214 ExtendedAttributeIdentList : IDENTIFIER EQUALS LPAREN IdentifierList RPAREN
9216 p[0] = (p[1], p[4])
9218 def p_IdentifierList(self, p):
9220 IdentifierList : IDENTIFIER Identifiers
9222 idents = list(p[2])
9223 # This is only used for identifier-list-valued extended attributes, and if
9224 # we're going to restrict to IDENTIFIER here we should at least allow
9225 # escaping with leading '_' as usual for identifiers.
9226 ident = p[1]
9227 if ident[0] == "_":
9228 ident = ident[1:]
9229 idents.insert(0, ident)
9230 p[0] = idents
9232 def p_IdentifiersList(self, p):
9234 Identifiers : COMMA IDENTIFIER Identifiers
9236 idents = list(p[3])
9237 # This is only used for identifier-list-valued extended attributes, and if
9238 # we're going to restrict to IDENTIFIER here we should at least allow
9239 # escaping with leading '_' as usual for identifiers.
9240 ident = p[2]
9241 if ident[0] == "_":
9242 ident = ident[1:]
9243 idents.insert(0, ident)
9244 p[0] = idents
9246 def p_IdentifiersEmpty(self, p):
9248 Identifiers :
9250 p[0] = []
9252 def p_error(self, p):
9253 if not p:
9254 raise WebIDLError(
9256 "Syntax Error at end of file. Possibly due to "
9257 "missing semicolon(;), braces(}) or both"
9259 [self._filename],
9261 else:
9262 raise WebIDLError(
9263 "invalid syntax",
9264 [Location(self.lexer, p.lineno, p.lexpos, self._filename)],
9267 def __init__(self, outputdir="", lexer=None):
9268 Tokenizer.__init__(self, outputdir, lexer)
9270 logger = SqueakyCleanLogger()
9271 try:
9272 self.parser = yacc.yacc(
9273 module=self,
9274 outputdir=outputdir,
9275 errorlog=logger,
9276 write_tables=False,
9277 # Pickling the grammar is a speedup in
9278 # some cases (older Python?) but a
9279 # significant slowdown in others.
9280 # We're not pickling for now, until it
9281 # becomes a speedup again.
9282 # , picklefile='WebIDLGrammar.pkl'
9284 finally:
9285 logger.reportGrammarErrors()
9287 self._globalScope = IDLScope(BuiltinLocation("<Global Scope>"), None, None)
9288 self._installBuiltins(self._globalScope)
9289 self._productions = []
9291 self._filename = "<builtin>"
9292 self.lexer.input(Parser._builtins)
9293 self._filename = None
9295 self.parser.parse(lexer=self.lexer, tracking=True)
9297 def _installBuiltins(self, scope):
9298 assert isinstance(scope, IDLScope)
9300 # range omits the last value.
9301 for x in range(
9302 IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1
9304 builtin = BuiltinTypes[x]
9305 identifier = IDLUnresolvedIdentifier(
9306 BuiltinLocation("<builtin type>"), builtin.name
9308 IDLTypedef(
9309 BuiltinLocation("<builtin type>"),
9310 scope,
9311 builtin,
9312 identifier,
9315 @staticmethod
9316 def handleNullable(type, questionMarkLocation):
9317 if questionMarkLocation is not None:
9318 type = IDLNullableType(questionMarkLocation, type)
9320 return type
9322 def parse(self, t, filename=None):
9323 self.lexer.input(t)
9325 # for tok in iter(self.lexer.token, None):
9326 # print tok
9328 self._filename = filename
9329 self._productions.extend(self.parser.parse(lexer=self.lexer, tracking=True))
9330 self._filename = None
9332 def finish(self):
9333 # If we have interfaces that are iterable, create their
9334 # iterator interfaces and add them to the productions array.
9335 interfaceStatements = []
9336 for p in self._productions:
9337 if isinstance(p, IDLInterface):
9338 interfaceStatements.append(p)
9340 for iface in interfaceStatements:
9341 iterable = None
9342 # We haven't run finish() on the interface yet, so we don't know
9343 # whether our interface is maplike/setlike/iterable or not. This
9344 # means we have to loop through the members to see if we have an
9345 # iterable member.
9346 for m in iface.members:
9347 if isinstance(m, (IDLIterable, IDLAsyncIterable)):
9348 iterable = m
9349 break
9350 if iterable and (iterable.isPairIterator() or iterable.isAsyncIterable()):
9352 def simpleExtendedAttr(str):
9353 return IDLExtendedAttribute(iface.location, (str,))
9355 if isinstance(iterable, IDLAsyncIterable):
9356 nextReturnType = IDLPromiseType(
9357 iterable.location, BuiltinTypes[IDLBuiltinType.Types.any]
9359 else:
9360 nextReturnType = BuiltinTypes[IDLBuiltinType.Types.object]
9361 nextMethod = IDLMethod(
9362 iterable.location,
9363 IDLUnresolvedIdentifier(iterable.location, "next"),
9364 nextReturnType,
9367 nextMethod.addExtendedAttributes([simpleExtendedAttr("Throws")])
9369 methods = [nextMethod]
9371 if iterable.getExtendedAttribute("GenerateReturnMethod"):
9372 assert isinstance(iterable, IDLAsyncIterable)
9374 returnMethod = IDLMethod(
9375 iterable.location,
9376 IDLUnresolvedIdentifier(iterable.location, "return"),
9377 IDLPromiseType(
9378 iterable.location, BuiltinTypes[IDLBuiltinType.Types.any]
9381 IDLArgument(
9382 iterable.location,
9383 IDLUnresolvedIdentifier(
9384 BuiltinLocation("<auto-generated-identifier>"),
9385 "value",
9387 BuiltinTypes[IDLBuiltinType.Types.any],
9388 optional=True,
9392 returnMethod.addExtendedAttributes([simpleExtendedAttr("Throws")])
9393 methods.append(returnMethod)
9395 if iterable.isIterable():
9396 itr_suffix = "Iterator"
9397 else:
9398 itr_suffix = "AsyncIterator"
9399 itr_ident = IDLUnresolvedIdentifier(
9400 iface.location, iface.identifier.name + itr_suffix
9402 if iterable.isIterable():
9403 classNameOverride = iface.identifier.name + " Iterator"
9404 elif iterable.isAsyncIterable():
9405 classNameOverride = iface.identifier.name + " AsyncIterator"
9406 itr_iface = IDLInterface(
9407 iface.location,
9408 self.globalScope(),
9409 itr_ident,
9410 None,
9411 methods,
9412 isKnownNonPartial=True,
9413 classNameOverride=classNameOverride,
9415 itr_iface.addExtendedAttributes(
9416 [simpleExtendedAttr("LegacyNoInterfaceObject")]
9418 # Make sure the exposure set for the iterator interface is the
9419 # same as the exposure set for the iterable interface, because
9420 # we're going to generate methods on the iterable that return
9421 # instances of the iterator.
9422 itr_iface._exposureGlobalNames = set(iface._exposureGlobalNames)
9423 # Always append generated iterable interfaces after the
9424 # interface they're a member of, otherwise nativeType generation
9425 # won't work correctly.
9426 if iterable.isIterable():
9427 itr_iface.iterableInterface = iface
9428 else:
9429 itr_iface.asyncIterableInterface = iface
9430 self._productions.append(itr_iface)
9431 iterable.iteratorType = IDLWrapperType(iface.location, itr_iface)
9433 # Make sure we finish IDLIncludesStatements before we finish the
9434 # IDLInterfaces.
9435 # XXX khuey hates this bit and wants to nuke it from orbit.
9436 includesStatements = [
9437 p for p in self._productions if isinstance(p, IDLIncludesStatement)
9439 otherStatements = [
9440 p for p in self._productions if not isinstance(p, IDLIncludesStatement)
9442 for production in includesStatements:
9443 production.finish(self.globalScope())
9444 for production in otherStatements:
9445 production.finish(self.globalScope())
9447 # Do any post-finish validation we need to do
9448 for production in self._productions:
9449 production.validate()
9451 # De-duplicate self._productions, without modifying its order.
9452 result = dict.fromkeys(self._productions)
9453 return list(result.keys())
9455 def reset(self):
9456 return Parser(lexer=self.lexer)
9458 # Builtin IDL defined by WebIDL
9459 _builtins = """
9460 typedef (ArrayBufferView or ArrayBuffer) BufferSource;
9464 def main():
9465 # Parse arguments.
9466 from optparse import OptionParser
9468 usageString = "usage: %prog [options] files"
9469 o = OptionParser(usage=usageString)
9470 o.add_option(
9471 "--cachedir",
9472 dest="cachedir",
9473 default=None,
9474 help="Directory in which to cache lex/parse tables.",
9476 o.add_option(
9477 "--verbose-errors",
9478 action="store_true",
9479 default=False,
9480 help="When an error happens, display the Python traceback.",
9482 (options, args) = o.parse_args()
9484 if len(args) < 1:
9485 o.error(usageString)
9487 fileList = args
9488 baseDir = os.getcwd()
9490 # Parse the WebIDL.
9491 parser = Parser(options.cachedir)
9492 try:
9493 for filename in fileList:
9494 fullPath = os.path.normpath(os.path.join(baseDir, filename))
9495 f = open(fullPath, "rb")
9496 lines = f.readlines()
9497 f.close()
9498 print(fullPath)
9499 parser.parse("".join(lines), fullPath)
9500 parser.finish()
9501 except WebIDLError as e:
9502 if options.verbose_errors:
9503 traceback.print_exc()
9504 else:
9505 print(e)
9508 if __name__ == "__main__":
9509 main()