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. """
13 from collections
import OrderedDict
, defaultdict
14 from itertools
import chain
16 from ply
import lex
, yacc
21 def parseInt(literal
):
32 if string
[0] == "0" and len(string
) > 1:
33 if string
[1] == "x" or string
[1] == "X":
42 value
= int(string
, base
)
46 # This is surprisingly faster than using the enum.IntEnum type (which doesn't
47 # support 'base' anyway)
48 def enum(*names
, base
=None):
50 names
= base
.attrs
+ names
52 class CustomEnumType(object):
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
71 return "%s: %s%s%s" % (
72 self
.warning
and "warning" or "error",
74 ", " if len(self
.locations
) != 0 else "",
75 "\n".join(self
.locations
),
79 class Location(object):
80 def __init__(self
, lexer
, lineno
, lexpos
, filename
):
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
94 startofline
= self
._lexdata
.rfind("\n", 0, self
._lexpos
) + 1
95 endofline
= self
._lexdata
.find("\n", self
._lexpos
, self
._lexpos
+ 80)
97 self
._line
= self
._lexdata
[startofline
:endofline
]
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
)
107 return "%s line %s:%s" % (self
.filename
, self
._lineno
, self
._colno
)
109 def _pointerline(self
):
110 return " " * self
._colno
+ "^"
114 return "%s line %s:%s\n%s\n%s" % (
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
146 class IDLObject(object):
147 __slots__
= "location", "userData", "filename"
149 def __init__(self
, location
):
150 self
.location
= location
152 self
.filename
= location
and location
.filename
154 def isInterface(self
):
157 def isNamespace(self
):
160 def isInterfaceMixin(self
):
166 def isCallback(self
):
172 def isDictionary(self
):
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
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.
217 if self
.filename
!= "<builtin>":
218 deps
.add(self
.filename
)
220 for d
in self
._getDependentObjects
():
221 deps
.update(d
.getDeps(visited
))
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
234 assert isinstance(identifier
, IDLIdentifier
)
235 self
._name
= identifier
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)
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"):
256 return name
.QName() + "::"
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
:
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
282 self
.addNewIdentifier(identifier
, object)
284 def addNewIdentifier(self
, identifier
, object):
287 self
._dict
[identifier
.name
] = object
289 def resolveIdentifierConflict(self
, scope
, identifier
, originalObject
, newObject
):
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
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
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" % (
330 originalObject
.location
,
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
)
364 assert isinstance(scope
, IDLScope
)
371 return self
.scope
.QName() + self
.name
374 return self
.QName().__hash
__()
376 def __eq__(self
, other
):
377 return self
.QName() == other
.QName()
380 return self
.scope
.lookupIdentifier(self
)
383 class IDLUnresolvedIdentifier(IDLObject
):
384 __slots__
= ("name",)
387 self
, location
, name
, allowDoubleUnderscore
=False, allowForbidden
=False
389 IDLObject
.__init
__(self
, location
)
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
:
400 if name
in ["constructor", "toString"] and not allowForbidden
:
402 "Cannot use reserved identifier '%s'" % (name
), [location
]
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
)
422 object.identifier
= identifier
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
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
):
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
):
460 def __init__(self
, location
, identifier
):
461 assert isinstance(identifier
, IDLUnresolvedIdentifier
)
462 IDLObjectWithIdentifier
.__init
__(self
, location
, None, identifier
)
464 def finish(self
, scope
):
466 scope
._lookupIdentifier
(self
.identifier
)
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
494 # Verify that our [Exposed] value, if any, makes sense.
495 for globalName
in self
._exposureGlobalNames
:
496 if globalName
not in scope
.globalNames
:
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
507 if len(scope
.globalNames
) != 0 and len(self
._exposureGlobalNames
) == 0:
510 "'%s' is not exposed anywhere even though we have "
511 "globals to be exposed to"
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
538 if not self
.isExposedInAnyWorker():
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
)
566 IDLObjectWithIdentifier
.__init
__(self
, location
, parentScope
, identifier
)
567 IDLObjectWithIdentifier
.resolve(self
, parentScope
)
569 def finish(self
, scope
):
575 def isIteratorInterface(self
):
578 def isAsyncIteratorInterface(self
):
581 def isExternal(self
):
584 def isInterface(self
):
587 def addExtendedAttributes(self
, attrs
):
590 "There are no extended attributes that are "
591 "allowed on external interfaces",
592 [attrs
[0].location
, self
.location
],
595 def resolve(self
, parentScope
):
598 def getJSImplementation(self
):
601 def isJSImplemented(self
):
604 def hasProbablyShortLivingWrapper(self
):
607 def _getDependentObjects(self
):
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
):
627 def finish(self
, scope
):
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
635 self
._nonPartialDictionary
.finish(scope
)
641 class IDLPartialInterfaceOrNamespace(IDLObject
):
645 "propagatedExtendedAttrs",
646 "_haveSecureContextExtendedAttribute",
647 "_nonPartialInterfaceOrNamespace",
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
):
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()
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()
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
])
696 "Unknown extended attribute %s on partial %s"
697 % (identifier
, self
._nonPartialInterfaceOrNamespace
.typeName()),
701 def finish(self
, scope
):
704 self
._finished
= True
706 not self
._haveSecureContextExtendedAttribute
707 and self
._nonPartialInterfaceOrNamespace
.getExtendedAttribute(
711 # This gets propagated to all our members.
712 for member
in self
.members
:
713 if member
.getExtendedAttribute("SecureContext"):
715 "[SecureContext] specified on both a "
716 "partial interface member and on the "
717 "non-partial interface",
720 self
._nonPartialInterfaceOrNamespace
.location
,
723 member
.addExtendedAttributes(
725 IDLExtendedAttribute(
726 self
._nonPartialInterfaceOrNamespace
.location
,
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
)
740 def convertExposedAttrToGlobalNameSet(exposedAttr
, targetSet
):
741 assert len(targetSet
) == 0
742 if exposedAttr
.hasValue():
743 targetSet
.add(exposedAttr
.value())
745 assert exposedAttr
.hasArgs()
746 targetSet
.update(exposedAttr
.args())
749 def globalNameSetToExposureSet(globalScope
, nameSet
, exposureSet
):
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
758 __slots__
= "static", "regular"
760 def __init__(self
, static
=None, regular
=None):
762 self
.regular
= regular
765 class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope
, IDLExposureMixins
):
771 "_isKnownNonPartial",
774 def __init__(self
, location
, parentScope
, name
):
775 assert isinstance(parentScope
, IDLScope
)
776 assert isinstance(name
, IDLUnresolvedIdentifier
)
778 self
._finished
= False
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
:
790 "%s does not have a non-partial declaration" % str(self
),
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)
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
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
840 if originalOperations
.regular
is None:
841 originalOperations
.regular
= newObject
842 return originalOperations
844 originalObject
= originalOperations
.regular
846 assert isinstance(originalObject
, IDLMethod
)
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
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
)
868 if self
.isInterface():
870 if self
.isNamespace():
872 assert self
.isInterfaceMixin()
873 return "interface mixin"
875 def addExtendedAttributes(self
, 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():
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()
897 "[SecureContext] specified on both an %s member and on "
898 "%s itself" % (typeName
, typeName
),
899 [member
.location
, attr
.location
],
901 member
.addExtendedAttributes([attr
])
904 "Unknown extended attribute %s on %s" % (identifier
, self
.typeName()),
908 def getExtendedAttribute(self
, name
):
909 return self
._extendedAttrDict
.get(name
, None)
911 def setNonPartial(self
, location
, members
):
912 if self
._isKnownNonPartial
:
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
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
):
954 for member
in self
.members
:
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
):
962 "Interface or interface mixin member has "
963 "larger exposure set than its container",
964 [member
.location
, self
.location
],
967 def isExternal(self
):
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
)
986 return "Interface mixin '%s'" % self
.identifier
.name
988 def isInterfaceMixin(self
):
991 def finish(self
, scope
):
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
1003 hasImplicitExposure
= len(self
._exposureGlobalNames
) == 0
1004 if hasImplicitExposure
:
1005 self
._exposureGlobalNames
.update(self
.actualExposureGlobalNames
)
1007 IDLInterfaceOrInterfaceMixinOrNamespace
.finish(self
, scope
)
1009 self
.finishMembers(scope
)
1012 for member
in self
.members
:
1016 "Interface mixin member cannot include "
1017 "an inherited attribute",
1018 [member
.location
, self
.location
],
1020 if member
.isStatic():
1022 "Interface mixin member cannot include a static member",
1023 [member
.location
, self
.location
],
1026 if member
.isMethod():
1027 if member
.isStatic():
1029 "Interface mixin member cannot include a static operation",
1030 [member
.location
, self
.location
],
1034 or member
.isSetter()
1035 or member
.isDeleter()
1036 or member
.isLegacycaller()
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):
1050 "totalMembersInSlots",
1053 def __init__(self
, slotIndex
):
1054 self
.slotIndex
= slotIndex
1055 self
.totalMembersInSlots
= 0
1058 class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace
):
1062 "maplikeOrSetlikeOrIterable",
1063 "legacyFactoryFunctions",
1064 "legacyWindowAliases",
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
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
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
)
1130 identifier
= IDLUnresolvedIdentifier(
1131 self
.location
, "constructor", allowForbidden
=True
1134 return self
._lookupIdentifier
(identifier
).static
1138 def isIterable(self
):
1140 self
.maplikeOrSetlikeOrIterable
1141 and self
.maplikeOrSetlikeOrIterable
.isIterable()
1144 def isAsyncIterable(self
):
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
):
1163 self
._finished
= True
1165 IDLInterfaceOrInterfaceMixinOrNamespace
.finish(self
, scope
)
1167 if len(self
.legacyWindowAliases
) > 0:
1168 if not self
.hasInterfaceObject():
1170 "Interface %s unexpectedly has [LegacyWindowAlias] "
1171 "and [LegacyNoInterfaceObject] together" % self
.identifier
.name
,
1174 if not self
.isExposedInWindow():
1176 "Interface %s has [LegacyWindowAlias] "
1177 "but not exposed in Window" % self
.identifier
.name
,
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():
1188 "%s declaration used on "
1189 "interface that is implemented in JS"
1190 % (member
.maplikeOrSetlikeOrIterableType
),
1193 if member
.valueType
.isObservableArray() or (
1194 member
.hasKeyType() and member
.keyType
.isObservableArray()
1197 "%s declaration uses ObservableArray as value or key type"
1198 % (member
.maplikeOrSetlikeOrIterableType
),
1201 # Check that we only have one interface declaration (currently
1202 # there can only be one maplike/setlike declaration per
1204 if self
.maplikeOrSetlikeOrIterable
:
1206 "%s declaration used on "
1207 "interface that already has %s "
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
):
1224 "%s inherits from %s which does not have "
1225 "a definition" % (self
.identifier
.name
, self
.parent
.identifier
.name
),
1228 if parent
and not isinstance(parent
, IDLInterface
):
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():
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.
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
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
):
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():
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():
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"):
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(
1314 ) and not self
.getExtendedAttribute("SecureContext"):
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
:
1326 cycleInGraph
= self
.findInterfaceLoopPoint(self
)
1329 "Interface %s has itself as ancestor" % self
.identifier
.name
,
1330 [self
.location
, cycleInGraph
.location
],
1333 self
.finishMembers(scope
)
1336 if ctor
is not None:
1337 if not self
.hasInterfaceObject():
1339 "Can't have both a constructor and [LegacyNoInterfaceObject]",
1340 [self
.location
, ctor
.location
],
1343 if self
.globalNames
:
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
:
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
)
1365 # Make a copy of our member list, so things that implement us
1366 # can get those without all the stuff we implement ourselves
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()
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
)
1388 ancestor
.maplikeOrSetlikeOrIterable
is not None
1389 and self
.maplikeOrSetlikeOrIterable
is not None
1392 "Cannot have maplike/setlike on %s that "
1393 "inherits %s, which is already "
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
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
):
1412 "LegacyUnforgeable interface %s does not have a "
1413 "stringifier" % self
.identifier
.name
,
1417 for m
in self
.members
:
1418 if m
.identifier
.name
== "toJSON":
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():
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
:
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
:
1444 member
.isMethod() and member
.getExtendedAttribute("CrossOriginCallable")
1448 member
.getExtendedAttribute("CrossOriginReadable")
1449 or member
.getExtendedAttribute("CrossOriginWritable")
1452 self
.hasCrossOriginMembers
= True
1455 if self
.hasCrossOriginMembers
:
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
:
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():
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
1490 if self
.parent
.reflectedHTMLAttributesReturningFrozenArray
:
1492 "Interface %s has at least one attribute marked "
1493 "as[ReflectedHTMLAttributeReturningFrozenArray],"
1494 "but one of its ancestors also has an attribute "
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
+= (
1517 member
.slotIndices
[self
.identifier
.name
] = self
.totalMembersInSlots
1518 self
.totalMembersInSlots
+= 1
1519 if member
.getExtendedAttribute("StoreInSlot"):
1520 self
._ownMembersInSlots
+= 1
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
1529 for unforgeableMember
in (
1531 for member
in self
.parent
.members
1532 if (member
.isAttr() or member
.isMethod())
1533 and member
.isLegacyUnforgeable()
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
]
1545 "Interface %s shadows [LegacyUnforgeable] "
1547 % (self
.identifier
.name
, ancestor
.identifier
.name
),
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
1564 while testInterface
:
1565 self
.maplikeOrSetlikeOrIterable
.checkCollisions(
1566 testInterface
.members
, isAncestor
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():
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"
1597 if memberType
!= "stringifiers" and memberType
!= "legacycallers":
1598 if member
.isNamed():
1599 memberType
= "named " + memberType
1601 assert member
.isIndexed()
1602 memberType
= "indexed " + memberType
1604 if memberType
in specialMembersSeen
:
1606 "Multiple " + memberType
+ " on %s" % (self
),
1609 specialMembersSeen
[memberType
].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
:
1620 "Interface with [LegacyUnenumerableNamedProperties] does "
1621 "not have a named getter",
1624 ancestor
= self
.parent
1626 if ancestor
.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
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
:
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"):
1647 "Interface with [Global] also has [LegacyOverrideBuiltIns]",
1650 # Mark all of our ancestors as being on the global's proto chain too
1651 parent
= self
.parent
1653 # Must not inherit from an interface with [LegacyOverrideBuiltIns]
1654 if parent
.getExtendedAttribute("LegacyOverrideBuiltIns"):
1656 "Interface with [Global] inherits from "
1657 "interface with [LegacyOverrideBuiltIns]",
1658 [self
.location
, parent
.location
],
1660 parent
._isOnGlobalProtoChain
= True
1661 parent
= parent
.parent
1664 def checkDuplicateNames(member
, name
, attributeName
):
1665 for m
in self
.members
:
1666 if m
.identifier
.name
== name
:
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
:
1674 "conflicting [%s=%s] definitions" % (attributeName
, name
),
1675 [member
.location
, m
.location
],
1677 if m
.isAttr() and m
!= member
and name
in m
.bindingAliases
:
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
1689 "%s is an unforgeable ancestor interface" % self
.identifier
.name
,
1694 if ctor
is not None:
1696 for namedCtor
in self
.legacyFactoryFunctions
:
1697 namedCtor
.validate()
1699 indexedGetter
= None
1700 hasLengthAttribute
= False
1701 for member
in self
.members
:
1704 if self
.isCallback() and member
.getExtendedAttribute("Replaceable"):
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.
1715 if member
.identifier
.name
== "length" and member
.type.isInteger():
1716 hasLengthAttribute
= True
1720 putForwards
= attr
.getExtendedAttribute("PutForwards")
1721 if putForwards
and self
.isCallback():
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
):
1733 for m
in iface
.members
:
1736 or m
.identifier
.name
!= putForwards
[0]
1741 "Cycle detected in forwarded "
1742 "assignments for attribute %s on "
1743 "%s" % (member
.identifier
.name
, self
),
1748 iface
= iface
.parent
1752 (forwardIface
, forwardAttr
) = findForwardedAttr(
1753 attr
.type.unroll().inner
1755 if forwardAttr
is None:
1757 "Attribute %s on %s forwards to "
1758 "missing attribute %s"
1759 % (attr
.identifier
.name
, iface
, putForwards
),
1763 iface
= forwardIface
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():
1776 "[Alias] must not be used on a "
1777 "[Global] interface operation",
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")
1789 "[Alias] must not be used on a "
1790 "conditionally exposed operation",
1793 if member
.isStatic():
1795 "[Alias] must not be used on a static operation",
1798 if member
.isIdentifierLess():
1800 "[Alias] must not be used on an "
1801 "identifierless operation",
1804 if member
.isLegacyUnforgeable():
1806 "[Alias] must not be used on an "
1807 "[LegacyUnforgeable] operation",
1811 checkDuplicateNames(member
, alias
, "Alias")
1813 # Check that the name of a [BindingAlias] doesn't conflict with an
1816 for bindingAlias
in member
.bindingAliases
:
1817 checkDuplicateNames(member
, bindingAlias
, "BindingAlias")
1819 # Conditional exposure makes no sense for interfaces with no
1821 # And SecureContext makes sense for interfaces with no interface object,
1822 # since it is also propagated to interface members.
1824 self
.isExposedConditionally(exclusions
=["SecureContext"])
1825 and not self
.hasInterfaceObject()
1828 "Interface with no interface object is exposed conditionally",
1832 # Value iterators are only allowed on interfaces with indexed getters,
1833 # and pair iterators are only allowed on interfaces without indexed
1835 if self
.isIterable():
1836 iterableDecl
= self
.maplikeOrSetlikeOrIterable
1837 if iterableDecl
.isValueIterator():
1838 if not indexedGetter
:
1840 "Interface with value iterator does not "
1841 "support indexed properties",
1842 [self
.location
, iterableDecl
.location
],
1845 if iterableDecl
.valueType
!= indexedGetter
.signatures()[0][0]:
1847 "Iterable type does not match indexed getter type",
1848 [iterableDecl
.location
, indexedGetter
.location
],
1851 if not hasLengthAttribute
:
1853 "Interface with value iterator does not "
1854 'have an integer-typed "length" attribute',
1855 [self
.location
, iterableDecl
.location
],
1858 assert iterableDecl
.isPairIterator()
1861 "Interface with pair iterator supports indexed properties",
1862 [self
.location
, iterableDecl
.location
, indexedGetter
.location
],
1865 if indexedGetter
and not hasLengthAttribute
:
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()
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
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
1896 for m
in self
.members
1897 if m
.isMethod() and not m
.isStatic()
1903 def inheritanceDepth(self
):
1905 parent
= self
.parent
1908 parent
= parent
.parent
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
):
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
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.
1952 if self
.parent
== otherInterface
:
1954 loopPoint
= self
.parent
.findInterfaceLoopPoint(otherInterface
)
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")
1969 assert isinstance(classId
, list)
1970 assert len(classId
) == 1
1973 def isJSImplemented(self
):
1974 return bool(self
.getJSImplementation())
1976 def hasProbablyShortLivingWrapper(self
):
1979 if current
.getExtendedAttribute("ProbablyShortLivingWrapper"):
1981 current
= current
.parent
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
)
1994 deps
.add(self
.parent
)
1997 def hasMembersInSlots(self
):
1998 return self
._ownMembersInSlots
!= 0
2000 conditionExtendedAttributes
= [
2008 def isExposedConditionally(self
, exclusions
=[]):
2010 ((a
not in exclusions
) and self
.getExtendedAttribute(a
))
2011 for a
in self
.conditionExtendedAttributes
2015 class IDLInterface(IDLInterfaceOrNamespace
):
2016 __slots__
= ("classNameOverride",)
2026 classNameOverride
=None,
2028 IDLInterfaceOrNamespace
.__init
__(
2029 self
, location
, parentScope
, name
, parent
, members
, isKnownNonPartial
2031 self
.classNameOverride
= classNameOverride
2034 return "Interface '%s'" % self
.identifier
.name
2036 def isInterface(self
):
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":
2049 "TreatNonCallableAsNull cannot be specified on interfaces",
2050 [attr
.location
, self
.location
],
2052 if identifier
== "LegacyTreatNonObjectAsNull":
2054 "LegacyTreatNonObjectAsNull cannot be specified on interfaces",
2055 [attr
.location
, self
.location
],
2057 elif identifier
== "LegacyNoInterfaceObject":
2058 if not attr
.noArguments():
2060 "[LegacyNoInterfaceObject] must take no arguments",
2064 self
._noInterfaceObject
= True
2065 elif identifier
== "LegacyFactoryFunction":
2066 if not attr
.hasValue():
2069 "LegacyFactoryFunction must either take an "
2070 "identifier or take a named argument list"
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
:
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():
2112 "[ExceptionClass] must take no arguments", [attr
.location
]
2116 "[ExceptionClass] must not be specified on "
2117 "an interface with inherited interfaces",
2118 [attr
.location
, self
.location
],
2120 elif identifier
== "Global":
2122 self
.globalNames
= [attr
.value()]
2123 elif attr
.hasArgs():
2124 self
.globalNames
= attr
.args()
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":
2134 self
.legacyWindowAliases
= [attr
.value()]
2135 elif attr
.hasArgs():
2136 self
.legacyWindowAliases
= attr
.args()
2139 "[%s] must either take an identifier "
2140 "or take an identifier list" % identifier
,
2143 for alias
in self
.legacyWindowAliases
:
2144 unresolved
= IDLUnresolvedIdentifier(attr
.location
, alias
)
2145 IDLObjectWithIdentifier(attr
.location
, self
.parentScope
, unresolved
)
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():
2161 "[%s] must take no arguments" % identifier
, [attr
.location
]
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():
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():
2180 "[%s] must have arguments" % identifier
, [attr
.location
]
2183 IDLInterfaceOrNamespace
.handleExtendedAttribute(self
, attr
)
2186 IDLInterfaceOrNamespace
.validate(self
)
2187 if self
.parent
and self
.isSerializable() and not self
.parent
.isSerializable():
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 "
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
):
2214 def __init__(self
, location
, parentScope
, name
, members
, isKnownNonPartial
):
2215 IDLInterfaceOrNamespace
.__init
__(
2216 self
, location
, parentScope
, name
, None, members
, isKnownNonPartial
2220 return "Namespace '%s'" % self
.identifier
.name
2222 def isNamespace(self
):
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
2234 if not attr
.hasValue():
2236 "[%s] must have a value" % identifier
, [attr
.location
]
2238 elif identifier
== "ProtoObjectHack" or identifier
== "ChromeOnly":
2239 if not attr
.noArguments():
2241 "[%s] must not have arguments" % identifier
, [attr
.location
]
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():
2252 "[%s] must have a value" % identifier
, [attr
.location
]
2255 IDLInterfaceOrNamespace
.handleExtendedAttribute(self
, attr
)
2257 def isSerializable(self
):
2261 class IDLDictionary(IDLObjectWithScope
):
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
)
2290 return "Dictionary '%s'" % self
.identifier
.name
2292 def isDictionary(self
):
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
):
2308 self
._finished
= True
2311 assert isinstance(self
.parent
, IDLIdentifierPlaceholder
)
2312 oldParent
= self
.parent
2313 self
.parent
= self
.parent
.finish(scope
)
2314 if not isinstance(self
.parent
, IDLDictionary
):
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
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
2344 if ancestor
== self
:
2346 "Dictionary %s has itself as an ancestor" % self
.identifier
.name
,
2347 [self
.identifier
.location
],
2349 inheritedMembers
.extend(ancestor
.members
)
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
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
:
2365 "Dictionary %s has two members with name %s"
2366 % (self
.identifier
.name
, member
.identifier
.name
),
2367 [member
.location
, inheritedMember
.location
],
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.
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
2401 return (True, [memberType
.location
] + locations
)
2403 if memberType
.isUnion():
2404 for member
in memberType
.flatMemberTypes
:
2405 (contains
, locations
) = typeContainsDictionary(member
, dictionary
)
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
)
2415 return (True, [member
.location
] + locations
)
2417 if dictMember
.parent
:
2418 if dictMember
.parent
== dictionary
:
2419 return (True, [dictMember
.location
])
2421 (contains
, locations
) = dictionaryContainsDictionary(
2422 dictMember
.parent
, dictionary
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():
2432 "Dictionary %s has member with nullable "
2433 "dictionary type" % self
.identifier
.name
,
2436 (contains
, locations
) = typeContainsDictionary(member
.type, self
)
2439 "Dictionary %s has member with itself as type."
2440 % self
.identifier
.name
,
2441 [member
.location
] + locations
,
2444 if member
.type.isUndefined():
2446 "Dictionary %s has member with undefined as its type."
2447 % self
.identifier
.name
,
2450 elif member
.type.isUnion():
2451 for unionMember
in member
.type.unroll().flatMemberTypes
:
2452 if unionMember
.isUndefined():
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
):
2464 identifier
= attr
.identifier()
2466 if identifier
== "GenerateInitFromJSON" or identifier
== "GenerateInit":
2467 if not attr
.noArguments():
2469 "[%s] must not have arguments" % identifier
, [attr
.location
]
2471 self
.needsConversionFromJS
= True
2473 identifier
== "GenerateConversionToJS" or identifier
== "GenerateToJSON"
2475 if not attr
.noArguments():
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():
2486 "[GenerateEqualityOperator] must take no arguments",
2489 self
.needsEqualityOperator
= self
2490 elif identifier
== "Unsorted":
2491 if not attr
.noArguments():
2493 "[Unsorted] must take no arguments", [attr
.location
]
2497 "[%s] extended attribute not allowed on "
2498 "dictionaries" % identifier
,
2502 self
._extendedAttrDict
[identifier
] = True
2504 def _getDependentObjects(self
):
2505 deps
= set(self
.members
)
2507 deps
.add(self
.parent
)
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
)):
2524 "Enum %s has multiple identical strings" % name
.name
, [location
]
2527 IDLObjectWithIdentifier
.__init
__(self
, location
, parentScope
, name
)
2528 self
._values
= values
2533 def finish(self
, scope
):
2542 def addExtendedAttributes(self
, attrs
):
2545 "There are no extended attributes that are allowed on enums",
2546 [attrs
[0].location
, self
.location
],
2549 def _getDependentObjects(self
):
2553 class IDLType(IDLObject
):
2564 # Additional primitive types
2566 "unrestricted_float",
2568 "unrestricted_double",
2569 # "double" last primitive type to match IDLBuiltinType
2595 "legacyNullToEmptyString",
2599 "_extendedAttrDict",
2602 def __init__(self
, location
, name
):
2603 IDLObject
.__init
__(self
, location
)
2605 self
.builtin
= False
2606 self
.legacyNullToEmptyString
= False
2608 self
._enforceRange
= False
2609 self
._allowShared
= False
2610 self
._extendedAttrDict
= {}
2617 + hash(self
._enforceRange
)
2618 + hash(self
.legacyNullToEmptyString
)
2619 + hash(self
._allowShared
)
2622 def __eq__(self
, 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
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
)
2653 def isPrimitive(self
):
2656 def isBoolean(self
):
2659 def isNumeric(self
):
2665 def isByteString(self
):
2668 def isDOMString(self
):
2671 def isUSVString(self
):
2674 def isUTF8String(self
):
2677 def isJSString(self
):
2680 def isUndefined(self
):
2683 def isSequence(self
):
2689 def isArrayBuffer(self
):
2692 def isArrayBufferView(self
):
2695 def isTypedArray(self
):
2698 def isBufferSource(self
):
2699 return self
.isArrayBuffer() or self
.isArrayBufferView() or self
.isTypedArray()
2701 def isCallbackInterface(self
):
2704 def isNonCallbackInterface(self
):
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
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()
2720 return self
.tag() == IDLType
.Tags
.any
2723 return self
.tag() == IDLType
.Tags
.object
2725 def isPromise(self
):
2728 def isComplete(self
):
2731 def includesRestrictedFloat(self
):
2737 def isUnrestricted(self
):
2738 # Should only call this on float types
2739 assert self
.isFloat()
2741 def isJSONType(self
):
2744 def isObservableArray(self
):
2747 def isDictionaryLike(self
):
2748 return self
.isDictionary() or self
.isRecord() or self
.isCallbackInterface()
2753 def hasEnforceRange(self
):
2754 return self
._enforceRange
2756 def hasAllowShared(self
):
2757 return self
._allowShared
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
):
2773 "Extended attributes on types only supported for builtins",
2774 [attrs
[0].location
, self
.location
],
2778 def getExtendedAttribute(self
, name
):
2779 return self
._extendedAttrDict
.get(name
, None)
2781 def resolveType(self
, parentScope
):
2787 def isDistinguishableFrom(self
, other
):
2789 "Can't tell whether a generic type is or is not "
2790 "distinguishable from other things"
2793 def isExposedInAllOf(self
, exposureSet
):
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
):
2811 def complete(self
, scope
):
2814 obj
= scope
._lookupIdentifier
(self
.name
)
2816 raise WebIDLError("Unresolved type '%s'." % self
.name
, [self
.location
])
2819 assert not obj
.isType()
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
):
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()
2862 return self
.inner
.unroll()
2864 def _getDependentObjects(self
):
2865 return self
.inner
._getDependentObjects
()
2868 class IDLNullableType(IDLParametrizedType
):
2871 def __init__(self
, location
, innerType
):
2872 assert not innerType
== BuiltinTypes
[IDLBuiltinType
.Types
.any
]
2874 IDLParametrizedType
.__init
__(self
, location
, None, innerType
)
2877 return hash(self
.inner
)
2879 def __eq__(self
, other
):
2880 return isinstance(other
, IDLNullableType
) and self
.inner
== other
.inner
2883 return self
.inner
.__str
__() + "OrNull"
2885 def prettyName(self
):
2886 return self
.inner
.prettyName() + "?"
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()
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()
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()
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()
2959 def isCallbackInterface(self
):
2960 return self
.inner
.isCallbackInterface()
2962 def isNonCallbackInterface(self
):
2963 return self
.inner
.isNonCallbackInterface()
2966 return self
.inner
.isEnum()
2969 return self
.inner
.isUnion()
2971 def isJSONType(self
):
2972 return self
.inner
.isJSONType()
2974 def isObservableArray(self
):
2975 return self
.inner
.isObservableArray()
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
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():
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
:
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",
3010 if self
.inner
.isDOMString():
3011 if self
.inner
.legacyNullToEmptyString
:
3013 "[LegacyNullToEmptyString] not allowed on a nullable DOMString",
3014 [self
.location
, self
.inner
.location
],
3016 if self
.inner
.isObservableArray():
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"
3025 def isDistinguishableFrom(self
, other
):
3028 or other
.isDictionary()
3030 other
.isUnion() and (other
.hasNullableType
or other
.hasDictionaryType())
3033 # Can't tell which type null should become
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"
3058 return hash(self
.inner
)
3060 def __eq__(self
, other
):
3061 return isinstance(other
, IDLSequenceType
) and self
.inner
== other
.inner
3064 return self
.inner
.__str
__() + "Sequence"
3066 def prettyName(self
):
3067 return "sequence<%s>" % self
.inner
.prettyName()
3069 def isSequence(self
):
3072 def isJSONType(self
):
3073 return self
.inner
.isJSONType()
3076 return IDLType
.Tags
.sequence
3078 def complete(self
, scope
):
3079 if self
.inner
.isObservableArray():
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"
3089 def isDistinguishableFrom(self
, other
):
3090 if other
.isPromise():
3093 # Just forward to the union; it'll deal
3094 return other
.isDistinguishableFrom(self
)
3097 or other
.isPrimitive()
3100 or other
.isInterface()
3101 or other
.isDictionary()
3102 or other
.isCallback()
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():
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"
3129 return hash(self
.inner
)
3131 def __eq__(self
, other
):
3132 return isinstance(other
, IDLRecordType
) and self
.inner
== other
.inner
3135 return self
.keyType
.__str
__() + self
.inner
.__str
__() + "Record"
3137 def prettyName(self
):
3138 return "record<%s, %s>" % (self
.keyType
.prettyName(), self
.inner
.prettyName())
3143 def isJSONType(self
):
3144 return self
.inner
.isJSONType()
3147 return IDLType
.Tags
.record
3149 def complete(self
, scope
):
3150 if self
.inner
.isObservableArray():
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"
3161 # We do not unroll our inner. Just stop at ourselves. That
3162 # lets us add headers for both ourselves and our inner as
3166 def isDistinguishableFrom(self
, other
):
3167 if other
.isPromise():
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
)
3179 or other
.isNonCallbackInterface()
3180 or other
.isSequence()
3183 def isExposedInAllOf(self
, exposureSet
):
3184 return self
.inner
.unroll().isExposedInAllOf(exposureSet
)
3187 class IDLObservableArrayType(IDLParametrizedType
):
3190 def __init__(self
, location
, innerType
):
3191 assert not innerType
.isUndefined()
3192 IDLParametrizedType
.__init
__(self
, location
, None, innerType
)
3195 return hash(self
.inner
)
3197 def __eq__(self
, other
):
3198 return isinstance(other
, IDLObservableArrayType
) and self
.inner
== other
.inner
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
):
3212 def isComplete(self
):
3213 return self
.name
is not None
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():
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():
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():
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():
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"
3250 def isDistinguishableFrom(self
, other
):
3251 # ObservableArrays are not distinguishable from anything.
3255 class IDLUnionType(IDLType
):
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
3276 assert self
.isComplete()
3277 return self
.name
.__hash
__()
3279 def prettyName(self
):
3280 return "(" + " or ".join(m
.prettyName() for m
in self
.memberTypes
) + ")"
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
)
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
):
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
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
)
3322 while i
< len(self
.flatMemberTypes
):
3323 if self
.flatMemberTypes
[i
].nullable():
3324 if self
.hasNullableType
:
3326 "Can't have more than one nullable types in a union",
3327 [nullableType
.location
, self
.flatMemberTypes
[i
].location
],
3329 if self
.hasDictionaryType():
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
3342 if self
.flatMemberTypes
[i
].isDictionary():
3343 if self
.hasNullableType
:
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
3356 for i
, t
in enumerate(self
.flatMemberTypes
[:-1]):
3357 for u
in self
.flatMemberTypes
[i
+ 1 :]:
3358 if not t
.isDistinguishableFrom(u
):
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
],
3368 def isDistinguishableFrom(self
, other
):
3369 if self
.hasNullableType
and other
.nullable():
3370 # Can't tell which type null should become
3373 otherTypes
= other
.unroll().memberTypes
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
):
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
:
3388 t
.unroll().isExposedInAllOf(set([globalName
]))
3389 for t
in self
.flatMemberTypes
3394 def hasDictionaryType(self
):
3395 return self
._dictionaryType
is not None
3397 def hasPossiblyEmptyDictionaryType(self
):
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
3415 return hash(self
.inner
)
3417 def __eq__(self
, other
):
3418 return isinstance(other
, IDLTypedefType
) and self
.inner
== other
.inner
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()
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()
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
):
3489 def complete(self
, parentScope
):
3490 if not self
.inner
.isComplete():
3491 self
.inner
= self
.inner
.complete(parentScope
)
3492 assert self
.inner
.isComplete()
3495 # Do we need a resolveType impl? I don't think it's particularly useful....
3498 return self
.inner
.tag()
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
)
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
)
3534 def isTypedef(self
):
3537 def addExtendedAttributes(self
, attrs
):
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
)
3554 self
._identifier
= inner
.identifier
3555 self
.builtin
= False
3558 return hash(self
._identifier
) + hash(self
.builtin
)
3560 def __eq__(self
, other
):
3562 isinstance(other
, IDLWrapperType
)
3563 and self
._identifier
== other
._identifier
3564 and self
.builtin
== other
.builtin
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()
3585 return isinstance(self
.inner
, IDLEnum
)
3587 def isJSONType(self
):
3588 if self
.isInterface():
3589 if self
.inner
.isExternal():
3593 if any(m
.isMethod() and m
.isToJSON() for m
in iface
.members
):
3595 iface
= iface
.parent
3599 elif self
.isDictionary():
3600 dictionary
= self
.inner
3602 if not all(m
.type.isJSONType() for m
in dictionary
.members
):
3604 dictionary
= dictionary
.parent
3608 "IDLWrapperType wraps type %s that we don't know if "
3609 "is serializable" % type(self
.inner
),
3613 def resolveType(self
, parentScope
):
3614 assert isinstance(parentScope
, IDLScope
)
3615 self
.inner
.resolve(parentScope
)
3617 def isComplete(self
):
3621 if self
.isInterface():
3622 return IDLType
.Tags
.interface
3624 return IDLType
.Tags
.enum
3625 elif self
.isDictionary():
3626 return IDLType
.Tags
.dictionary
3630 def isDistinguishableFrom(self
, other
):
3631 if other
.isPromise():
3634 # Just forward to the union; it'll deal
3635 return other
.isDistinguishableFrom(self
)
3636 assert self
.isInterface() or self
.isEnum() or self
.isDictionary()
3640 or other
.isPrimitive()
3641 or other
.isInterface()
3643 or other
.isCallback()
3644 or other
.isDictionary()
3645 or other
.isSequence()
3648 if self
.isDictionary() and other
.nullable():
3654 or other
.isSequence()
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
)
3669 other
.isNonCallbackInterface()
3671 or other
.isUndefined()
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():
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
3697 self
.inner
.interfacesBasedOnSelf
3698 & other
.unroll().inner
.interfacesBasedOnSelf
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()
3710 def isExposedInAllOf(self
, exposureSet
):
3711 if not self
.isInterface():
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.
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
])
3746 class IDLPromiseType(IDLParametrizedType
):
3749 def __init__(self
, location
, innerType
):
3750 IDLParametrizedType
.__init
__(self
, location
, "Promise", innerType
)
3753 return hash(self
.promiseInnerType())
3755 def __eq__(self
, other
):
3757 isinstance(other
, IDLPromiseType
)
3758 and self
.promiseInnerType() == other
.promiseInnerType()
3762 return self
.inner
.__str
__() + "Promise"
3764 def prettyName(self
):
3765 return "Promise<%s>" % self
.inner
.prettyName()
3767 def isPromise(self
):
3770 def promiseInnerType(self
):
3774 return IDLType
.Tags
.promise
3776 def complete(self
, scope
):
3777 if self
.inner
.isObservableArray():
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
)
3787 # We do not unroll our inner. Just stop at ourselves. That
3788 # lets us add headers for both ourselves and our inner as
3792 def isDistinguishableFrom(self
, other
):
3793 # Promises are not distinguishable from anything.
3796 def isExposedInAllOf(self
, exposureSet
):
3797 # Check the internal type
3798 return self
.promiseInnerType().unroll().isExposedInAllOf(exposureSet
)
3801 class IDLBuiltinType(IDLType
):
3811 "unsigned_long_long",
3812 # Additional primitive types
3814 "unrestricted_float",
3816 "unrestricted_double",
3817 # IMPORTANT: "double" must be the last primitive type listed
3833 "Uint8ClampedArray",
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
,
3879 Types
.octet
: "octet",
3880 Types
.short
: "short",
3881 Types
.unsigned_short
: "unsigned short",
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",
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",
3916 "_withLegacyNullToEmptyString",
3927 legacyNullToEmptyString
=False,
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
)
3940 self
._typeTag
= type
3941 self
._clamped
= None
3942 self
._rangeEnforced
= None
3943 self
._withLegacyNullToEmptyString
= None
3944 self
._withAllowShared
= None
3945 if self
.isInteger():
3948 self
.name
= "Clamped" + self
.name
3949 self
._extendedAttrDict
["Clamp"] = True
3951 self
._enforceRange
= True
3952 self
.name
= "RangeEnforced" + self
.name
3953 self
._extendedAttrDict
["EnforceRange"] = True
3954 elif clamp
or enforceRange
:
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
:
3965 "Non-string types cannot be [LegacyNullToEmptyString]", attrLocation
3967 if self
.isBufferSource():
3969 self
._allowShared
= True
3970 self
._extendedAttrDict
["AllowShared"] = True
3973 "Types that are not buffer source types cannot be [AllowShared]",
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(
3993 attrLocation
=attrLocation
,
3995 return self
._clamped
3997 def rangeEnforced(self
, attrLocation
):
3998 if not self
._rangeEnforced
:
3999 self
._rangeEnforced
= IDLBuiltinType(
4004 attrLocation
=attrLocation
,
4006 return self
._rangeEnforced
4008 def withLegacyNullToEmptyString(self
, attrLocation
):
4009 if not self
._withLegacyNullToEmptyString
:
4010 self
._withLegacyNullToEmptyString
= IDLBuiltinType(
4014 legacyNullToEmptyString
=True,
4015 attrLocation
=attrLocation
,
4017 return self
._withLegacyNullToEmptyString
4019 def withAllowShared(self
, attrLocation
):
4020 if not self
._withAllowShared
:
4021 self
._withAllowShared
= IDLBuiltinType(
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()
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
):
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()
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()
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()
4113 return IDLBuiltinType
.TagLookup
[self
._typeTag
]
4115 def isDistinguishableFrom(self
, other
):
4116 if other
.isPromise():
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():
4128 or other
.isInterface()
4130 or other
.isCallback()
4131 or other
.isDictionary()
4132 or other
.isSequence()
4136 if self
.isBoolean():
4137 return other
.isNumeric()
4138 assert self
.isNumeric()
4139 return other
.isBoolean()
4143 or other
.isPrimitive()
4144 or other
.isInterface()
4146 or other
.isCallback()
4147 or other
.isDictionary()
4148 or other
.isSequence()
4152 # Can't tell "any" apart from anything
4157 or other
.isPrimitive()
4161 # Not much else we could be!
4162 assert self
.isSpiderMonkeyInterface()
4163 # Like interfaces, but we know we're not a callback
4166 or other
.isPrimitive()
4169 or other
.isCallback()
4170 or other
.isDictionary()
4171 or other
.isSequence()
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
4193 and not other
.isArrayBufferView()
4194 and not (other
.isTypedArray() and other
.name
== self
.name
)
4200 def _getDependentObjects(self
):
4203 def withExtendedAttributes(self
, attrs
):
4205 for attribute
in attrs
:
4206 identifier
= attribute
.identifier()
4207 if identifier
== "Clamp":
4208 if not attribute
.noArguments():
4210 "[Clamp] must take no arguments", [attribute
.location
]
4212 if ret
.hasEnforceRange() or self
._enforceRange
:
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():
4221 "[EnforceRange] must take no arguments", [attribute
.location
]
4223 if ret
.hasClamp() or self
._clamp
:
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()):
4232 "[LegacyNullToEmptyString] only allowed on DOMStrings and UTF8Strings",
4233 [self
.location
, attribute
.location
],
4235 assert not self
.nullable()
4236 if attribute
.hasValue():
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():
4247 "[AllowShared] must take no arguments", [attribute
.location
]
4249 if not self
.isBufferSource():
4251 "[AllowShared] only allowed on buffer source types",
4252 [self
.location
, attribute
.location
],
4254 ret
= self
.withAllowShared([self
.location
, attribute
.location
])
4258 "Unhandled extended attribute on type",
4259 [self
.location
, attribute
.location
],
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>"),
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>"),
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>"),
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>"),
4341 IDLBuiltinType
.Types
.ArrayBuffer
,
4343 IDLBuiltinType
.Types
.ArrayBufferView
: IDLBuiltinType(
4344 BuiltinLocation("<builtin type>"),
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>"),
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>"),
4373 IDLBuiltinType
.Types
.Uint32Array
,
4375 IDLBuiltinType
.Types
.Float32Array
: IDLBuiltinType(
4376 BuiltinLocation("<builtin type>"),
4378 IDLBuiltinType
.Types
.Float32Array
,
4380 IDLBuiltinType
.Types
.Float64Array
: IDLBuiltinType(
4381 BuiltinLocation("<builtin type>"),
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]
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
):
4422 def __init__(self
, location
, type, value
):
4423 IDLObject
.__init
__(self
, location
)
4425 assert isinstance(type, IDLType
)
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.
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
:
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
4455 if isinstance(e
, WebIDLError
) and not isinstance(
4456 e
, NoCoercionFoundError
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
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:
4474 return IDLValue(self
.location
, type, self
.value
)
4477 "Value %s is out of range for type %s." % (self
.value
, type),
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
))
4486 "Converting value %s to %s will lose precision."
4487 % (self
.value
, type),
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():
4495 "'%s' is not a valid default value for enum %s"
4496 % (self
.value
, enum
.identifier
.name
),
4497 [location
, enum
.location
],
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
)
4507 "Trying to convert unrestricted value %s to non-unrestricted"
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()
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.
4528 " " + string
.ascii_letters
+ string
.digits
+ string
.punctuation
4530 for idx
, c
in enumerate(self
.value
):
4531 if c
not in valid_ascii_lit
:
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
),
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
4545 raise NoCoercionFoundError(
4546 "Cannot coerce type %s to type %s." % (self
.type, type), [location
]
4549 def _getDependentObjects(self
):
4553 class IDLNullValue(IDLObject
):
4554 __slots__
= "type", "value"
4556 def __init__(self
, location
):
4557 IDLObject
.__init
__(self
, location
)
4561 def coerceToType(self
, type, location
):
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.
4573 for t
in type.flatMemberTypes
:
4574 if t
.isDictionary():
4577 nullValue
.type = type
4580 def _getDependentObjects(self
):
4584 class IDLEmptySequenceValue(IDLObject
):
4585 __slots__
= "type", "value"
4587 def __init__(self
, location
):
4588 IDLObject
.__init
__(self
, location
)
4592 def coerceToType(self
, type, location
):
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
:
4599 return self
.coerceToType(subtype
, location
)
4603 if not type.isSequence():
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
):
4616 class IDLDefaultDictionaryValue(IDLObject
):
4617 __slots__
= "type", "value"
4619 def __init__(self
, location
):
4620 IDLObject
.__init
__(self
, location
)
4624 def coerceToType(self
, type, location
):
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
:
4631 return self
.coerceToType(subtype
, location
)
4635 if not type.isDictionary():
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
):
4648 class IDLUndefinedValue(IDLObject
):
4649 __slots__
= "type", "value"
4651 def __init__(self
, location
):
4652 IDLObject
.__init
__(self
, location
)
4656 def coerceToType(self
, type, location
):
4657 if not type.isAny():
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
):
4670 class IDLInterfaceMember(IDLObjectWithIdentifier
, IDLExposureMixins
):
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
)
4685 if extendedAttrDict
is None:
4686 self
._extendedAttrDict
= {}
4688 self
._extendedAttrDict
= extendedAttrDict
4691 return self
.tag
== IDLInterfaceMember
.Tags
.Method
4694 return self
.tag
== IDLInterfaceMember
.Tags
.Attr
4697 return self
.tag
== IDLInterfaceMember
.Tags
.Const
4699 def isMaplikeOrSetlikeOrIterable(self
):
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
):
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
):
4720 def getExtendedAttribute(self
, name
):
4721 return self
._extendedAttrDict
.get(name
, None)
4723 def finish(self
, scope
):
4724 IDLExposureMixins
.finish(self
, scope
)
4727 if self
.isAttr() or self
.isMethod():
4728 if self
.affects
== "Everything" and self
.dependsOn
!= "Everything":
4730 "Interface member is flagged as affecting "
4731 "everything but not depending on everything. "
4732 "That seems rather unlikely.",
4736 if self
.getExtendedAttribute("NewObject"):
4737 if self
.dependsOn
== "Nothing" or self
.dependsOn
== "DOMState":
4739 "A [NewObject] method is not idempotent, "
4740 "so it has to depend on something other than DOM state.",
4743 if self
.getExtendedAttribute("Cached") or self
.getExtendedAttribute(
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.",
4755 def _setDependsOn(self
, dependsOn
):
4756 if self
.dependsOn
!= "Everything":
4758 "Trying to specify multiple different DependsOn, "
4759 "Pure, or Constant extended attributes for "
4763 if dependsOn
not in IDLInterfaceMember
.DependsOnValues
:
4765 "Invalid [DependsOn=%s] on attribute" % dependsOn
, [self
.location
]
4767 self
.dependsOn
= dependsOn
4769 def _setAffects(self
, affects
):
4770 if self
.affects
!= "Everything":
4772 "Trying to specify multiple different Affects, "
4773 "Pure, or Constant extended attributes for "
4777 if affects
not in IDLInterfaceMember
.AffectsValues
:
4779 "Invalid [Affects=%s] on attribute" % affects
, [self
.location
]
4781 self
.affects
= affects
4783 def _addAlias(self
, alias
):
4784 if alias
in self
.aliases
:
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
:
4793 "Duplicate [BindingAlias=%s] on attribute" % bindingAlias
,
4796 self
.bindingAliases
.append(bindingAlias
)
4799 class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember
):
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
)
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 (
4848 member
.isStatic() or member
.isMaplikeOrSetlikeOrIterableMethod()
4851 or (member
.isAttr() and member
.isMaplikeOrSetlikeAttr())
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.
4863 isAncestor
or member
.isAttr() or member
.isConst()
4864 ) and member
.identifier
.name
in self
.disallowedNonMethodNames
:
4866 "Member '%s' conflicts "
4867 "with reserved %s method."
4868 % (member
.identifier
.name
, self
.maplikeOrSetlikeOrIterableType
),
4869 [self
.location
, member
.location
],
4876 allowExistingOperations
,
4881 affectsNothing
=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
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
4910 if not allowExistingOperations
:
4911 self
.disallowedMemberNames
.append(name
)
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
:
4919 if m
.identifier
.name
== name
and m
.isMethod() and not m
.isStatic():
4923 IDLUnresolvedIdentifier(
4924 self
.location
, name
, allowDoubleUnderscore
=chromeOnly
4928 maplikeOrSetlikeOrIterable
=self
,
4930 # We need to be able to throw from declaration methods
4931 method
.addExtendedAttributes([IDLExtendedAttribute(self
.location
, ("Throws",))])
4933 method
.addExtendedAttributes(
4934 [IDLExtendedAttribute(self
.location
, ("ChromeOnly",))]
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.
4943 method
.addExtendedAttributes(
4945 IDLExtendedAttribute(self
.location
, ("DependsOn", "Everything")),
4946 IDLExtendedAttribute(self
.location
, ("Affects", "Nothing")),
4950 method
.addExtendedAttributes(
4951 [IDLExtendedAttribute(self
.location
, ("NewObject",))]
4954 if not self
.isAsyncIterable():
4955 method
.addExtendedAttributes(
4956 [IDLExtendedAttribute(self
.location
, ("Alias", "@@iterator"))]
4959 method
.addExtendedAttributes(
4960 [IDLExtendedAttribute(self
.location
, ("Alias", "@@asyncIterator"))]
4962 members
.append(method
)
4964 def resolve(self
, parentScope
):
4966 self
.keyType
.resolveType(parentScope
)
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
)
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
)
4988 IDLInterfaceMember
.validate(self
)
4990 def handleExtendedAttribute(self
, attr
):
4991 IDLInterfaceMember
.handleExtendedAttribute(self
, attr
)
4993 def _getDependentObjects(self
):
4996 deps
.add(self
.keyType
)
4998 deps
.add(self
.valueType
)
5001 def getForEachArguments(self
):
5005 IDLUnresolvedIdentifier(
5006 BuiltinLocation("<auto-generated-identifier>"), "callback"
5008 BuiltinTypes
[IDLBuiltinType
.Types
.object],
5012 IDLUnresolvedIdentifier(
5013 BuiltinLocation("<auto-generated-identifier>"), "thisArg"
5015 BuiltinTypes
[IDLBuiltinType
.Types
.any
],
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
__(
5034 IDLInterfaceMember
.Tags
.Iterable
,
5036 self
.iteratorType
= None
5039 return "declared iterable with key '%s' and value '%s'" % (
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():
5061 affectsNothing
=True,
5063 isIteratorAlias
=True,
5071 affectsNothing
=True,
5080 affectsNothing
=True,
5084 # undefined forEach(callback(valueType, keyType), optional any thisArg)
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
):
5105 if not arg
.optional
:
5107 "The arguments of the asynchronously iterable declaration on "
5108 "%s must all be optional arguments." % identifier
,
5112 IDLMaplikeOrSetlikeOrIterableBase
.__init
__(
5119 IDLInterfaceMember
.Tags
.AsyncIterable
,
5121 self
.iteratorType
= None
5122 self
.argList
= argList
5125 return "declared async iterable with key '%s' and value '%s'" % (
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.
5143 affectsNothing
=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():
5152 # Methods can't share their IDLArguments, so we need to make copies here.
5153 def copyArgList(argList
):
5154 return map(copy
.copy
, argList
)
5162 copyArgList(self
.argList
),
5163 affectsNothing
=True,
5165 isIteratorAlias
=True,
5173 copyArgList(self
.argList
),
5174 affectsNothing
=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"
5190 self
, location
, identifier
, maplikeOrSetlikeType
, readonly
, keyType
, valueType
5192 IDLMaplikeOrSetlikeOrIterableBase
.__init
__(
5196 maplikeOrSetlikeType
,
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():
5208 elif self
.isSetlike():
5212 return "declared '%s' with key '%s'" % (
5213 self
.maplikeOrSetlikeOrIterableType
,
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
5227 IDLUnresolvedIdentifier(
5228 BuiltinLocation("<auto-generated-identifier>"), "size"
5230 BuiltinTypes
[IDLBuiltinType
.Types
.unsigned_long
],
5232 maplikeOrSetlike
=self
,
5235 self
.reserved_ro_names
= ["size"]
5236 self
.disallowedMemberNames
.append("size")
5243 BuiltinTypes
[IDLBuiltinType
.Types
.object],
5244 affectsNothing
=True,
5245 isIteratorAlias
=self
.isMaplike(),
5252 BuiltinTypes
[IDLBuiltinType
.Types
.object],
5253 affectsNothing
=True,
5260 BuiltinTypes
[IDLBuiltinType
.Types
.object],
5261 affectsNothing
=True,
5262 isIteratorAlias
=self
.isSetlike(),
5265 # undefined forEach(callback(valueType, keyType), thisVal)
5270 BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
5271 self
.getForEachArguments(),
5277 IDLUnresolvedIdentifier(self
.location
, "key"),
5281 # boolean has(keyType key)
5286 BuiltinTypes
[IDLBuiltinType
.Types
.boolean
],
5291 if not self
.readonly
:
5294 "clear", members
, True, BuiltinTypes
[IDLBuiltinType
.Types
.undefined
], []
5296 # boolean delete(keyType key)
5301 BuiltinTypes
[IDLBuiltinType
.Types
.boolean
],
5305 if self
.isSetlike():
5306 if not self
.readonly
:
5307 # Add returns the set object it just added to.
5308 # object add(keyType key)
5314 BuiltinTypes
[IDLBuiltinType
.Types
.object],
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
5333 BuiltinTypes
[IDLBuiltinType
.Types
.any
],
5341 IDLUnresolvedIdentifier(self
.location
, "value"),
5345 if not self
.readonly
:
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():
5366 "A constant cannot be of a dictionary type", [self
.location
]
5369 raise WebIDLError("A constant cannot be of a record type", [self
.location
])
5373 if identifier
.name
== "prototype":
5375 "The identifier of a constant must not be 'prototype'", [location
]
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
]
5389 locations
.append(type.inner
.location
)
5392 raise WebIDLError("Incorrect type for constant", locations
)
5395 # The value might not match the type
5396 coercedValue
= self
.value
.coerceToType(self
.type, self
.location
)
5399 self
.value
= coercedValue
5402 IDLInterfaceMember
.validate(self
)
5404 def handleExtendedAttribute(self
, attr
):
5405 identifier
= attr
.identifier()
5406 if identifier
== "Exposed":
5407 convertExposedAttrToGlobalNameSet(attr
, self
._exposureGlobalNames
)
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
5420 "Unknown extended attribute %s on constant" % identifier
,
5423 IDLInterfaceMember
.handleExtendedAttribute(self
, attr
)
5425 def _getDependentObjects(self
):
5426 return set([self
.type, self
.value
])
5429 class IDLAttribute(IDLInterfaceMember
):
5435 "legacyLenientThis",
5436 "_legacyUnforgeable",
5454 maplikeOrSetlike
=None,
5455 extendedAttrDict
=None,
5457 IDLInterfaceMember
.__init
__(
5461 IDLInterfaceMember
.Tags
.Attr
,
5462 extendedAttrDict
=extendedAttrDict
,
5465 assert isinstance(type, IDLType
)
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
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":
5488 "The identifier of a static attribute must not be 'prototype'",
5492 if readonly
and inherit
:
5494 "An attribute cannot be both 'readonly' and 'inherit'", [self
.location
]
5500 def forceStatic(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
)
5517 if self
.readonly
and (
5518 self
.type.hasClamp()
5519 or self
.type.hasEnforceRange()
5520 or self
.type.hasAllowShared()
5521 or self
.type.legacyNullToEmptyString
5524 "A readonly attribute cannot be [Clamp] or [EnforceRange] or [AllowShared]",
5527 if self
.type.isDictionary() and not self
.getExtendedAttribute("Cached"):
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")
5536 "A non-cached attribute cannot be of a sequence type",
5539 if self
.type.isRecord() and not self
.getExtendedAttribute("Cached"):
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():
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 "
5552 [self
.location
, f
.location
],
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 "
5561 [self
.location
, f
.location
],
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 "
5570 [self
.location
, f
.location
],
5572 if not self
.type.isInterface() and self
.getExtendedAttribute("PutForwards"):
5574 "An attribute with [PutForwards] must have an "
5575 "interface type as its type",
5579 if not self
.type.isInterface() and self
.getExtendedAttribute("SameObject"):
5581 "An attribute with [SameObject] must have an "
5582 "interface type as its type",
5586 if self
.type.isPromise() and not self
.readonly
:
5588 "Promise-returning attributes must be readonly", [self
.location
]
5591 if self
.type.isObservableArray():
5594 "A static attribute cannot have an ObservableArray type",
5597 if self
.getExtendedAttribute("Cached") or self
.getExtendedAttribute(
5601 "[Cached] and [StoreInSlot] must not be used "
5602 "on an attribute whose type is ObservableArray",
5607 def typeContainsChromeOnlyDictionaryMember(type):
5608 if type.nullable() or type.isSequence() or type.isRecord():
5609 return typeContainsChromeOnlyDictionaryMember(type.inner
)
5612 for memberType
in type.flatMemberTypes
:
5613 (contains
, location
) = typeContainsChromeOnlyDictionaryMember(
5617 return (True, location
)
5619 if type.isDictionary():
5620 dictionary
= type.inner
5622 (contains
, location
) = dictionaryContainsChromeOnlyMember(
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(
5639 return (True, location
)
5640 return (False, None)
5642 IDLInterfaceMember
.validate(self
)
5644 if self
.getExtendedAttribute("Cached") or self
.getExtendedAttribute(
5647 if not self
.affects
== "Nothing":
5649 "Cached attributes and attributes stored in "
5650 "slots must be Constant or Pure or "
5651 "Affects=Nothing, since the getter won't always "
5655 (contains
, location
) = typeContainsChromeOnlyDictionaryMember(self
.type)
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"):
5665 not self
.type.isSequence()
5666 and not self
.type.isDictionary()
5667 and not self
.type.isRecord()
5670 "[Frozen] is only allowed on "
5671 "sequence-valued, dictionary-valued, and "
5672 "record-valued attributes",
5675 if self
.getExtendedAttribute("ReflectedHTMLAttributeReturningFrozenArray"):
5676 if self
.getExtendedAttribute("Cached") or self
.getExtendedAttribute(
5680 "[ReflectedHTMLAttributeReturningFrozenArray] can't be combined "
5681 "with [Cached] or [StoreInSlot]",
5684 if not self
.type.isSequence():
5686 "[ReflectedHTMLAttributeReturningFrozenArray] is only allowed on "
5687 "sequence-valued attributes",
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()
5699 not sequenceMemberType
.isInterface()
5700 or not interfaceTypeIsOrInheritsFromElement(sequenceMemberType
.inner
)
5703 "[ReflectedHTMLAttributeReturningFrozenArray] is only allowed on "
5704 "sequence-valued attributes containing interface values of type "
5705 "Element or an interface inheriting from Element",
5708 if not self
.type.unroll().isExposedInAllOf(self
.exposureSet
):
5710 "Attribute returns a type that is not exposed "
5711 "everywhere where the attribute is exposed",
5714 if self
.getExtendedAttribute("CEReactions"):
5717 "[CEReactions] is not allowed on readonly attributes",
5721 def handleExtendedAttribute(self
, attr
):
5722 identifier
= attr
.identifier()
5724 identifier
== "SetterThrows"
5725 or identifier
== "SetterCanOOM"
5726 or identifier
== "SetterNeedsSubjectPrincipal"
5727 ) and self
.readonly
:
5729 "Readonly attributes must not be flagged as [%s]" % identifier
,
5732 elif identifier
== "BindingAlias":
5733 if not attr
.hasValue():
5735 "[BindingAlias] takes an identifier or string", [attr
.location
]
5737 self
._addBindingAlias
(attr
.value())
5740 identifier
== "Throws"
5741 or identifier
== "GetterThrows"
5742 or identifier
== "CanOOM"
5743 or identifier
== "GetterCanOOM"
5745 and self
.getExtendedAttribute("StoreInSlot")
5747 identifier
== "StoreInSlot"
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():
5759 "[LegacyLenientThis] must take no arguments", [attr
.location
]
5763 "[LegacyLenientThis] is only allowed on non-static attributes",
5764 [attr
.location
, self
.location
],
5766 if self
.getExtendedAttribute("CrossOriginReadable"):
5768 "[LegacyLenientThis] is not allowed in combination "
5769 "with [CrossOriginReadable]",
5770 [attr
.location
, self
.location
],
5772 if self
.getExtendedAttribute("CrossOriginWritable"):
5774 "[LegacyLenientThis] is not allowed in combination "
5775 "with [CrossOriginWritable]",
5776 [attr
.location
, self
.location
],
5778 self
.legacyLenientThis
= True
5779 elif identifier
== "LegacyUnforgeable":
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
:
5788 "[SameObject] only allowed on readonly attributes",
5789 [attr
.location
, self
.location
],
5791 elif identifier
== "Constant" and not self
.readonly
:
5793 "[Constant] only allowed on readonly attributes",
5794 [attr
.location
, self
.location
],
5796 elif identifier
== "PutForwards":
5797 if not self
.readonly
:
5799 "[PutForwards] is only allowed on readonly attributes",
5800 [attr
.location
, self
.location
],
5802 if self
.type.isPromise():
5804 "[PutForwards] is not allowed on Promise-typed attributes",
5805 [attr
.location
, self
.location
],
5809 "[PutForwards] is only allowed on non-static attributes",
5810 [attr
.location
, self
.location
],
5812 if self
.getExtendedAttribute("Replaceable") is not None:
5814 "[PutForwards] and [Replaceable] can't both "
5815 "appear on the same attribute",
5816 [attr
.location
, self
.location
],
5818 if not attr
.hasValue():
5820 "[PutForwards] takes an identifier", [attr
.location
, self
.location
]
5822 elif identifier
== "Replaceable":
5823 if not attr
.noArguments():
5825 "[Replaceable] must take no arguments", [attr
.location
]
5827 if not self
.readonly
:
5829 "[Replaceable] is only allowed on readonly attributes",
5830 [attr
.location
, self
.location
],
5832 if self
.type.isPromise():
5834 "[Replaceable] is not allowed on Promise-typed attributes",
5835 [attr
.location
, self
.location
],
5839 "[Replaceable] is only allowed on non-static attributes",
5840 [attr
.location
, self
.location
],
5842 if self
.getExtendedAttribute("PutForwards") is not None:
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():
5851 "[LegacyLenientSetter] must take no arguments", [attr
.location
]
5853 if not self
.readonly
:
5855 "[LegacyLenientSetter] is only allowed on readonly attributes",
5856 [attr
.location
, self
.location
],
5858 if self
.type.isPromise():
5860 "[LegacyLenientSetter] is not allowed on "
5861 "Promise-typed attributes",
5862 [attr
.location
, self
.location
],
5866 "[LegacyLenientSetter] is only allowed on non-static attributes",
5867 [attr
.location
, self
.location
],
5869 if self
.getExtendedAttribute("PutForwards") is not None:
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:
5877 "[LegacyLenientSetter] and [Replaceable] can't both "
5878 "appear on the same attribute",
5879 [attr
.location
, self
.location
],
5881 elif identifier
== "LenientFloat":
5884 "[LenientFloat] used on a readonly attribute",
5885 [attr
.location
, self
.location
],
5887 if not self
.type.includesRestrictedFloat():
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"):
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"):
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():
5910 "[%s] must take no arguments" % identifier
, [attr
.location
]
5914 "[%s] is only allowed on non-static attributes" % identifier
,
5915 [attr
.location
, self
.location
],
5917 if self
.getExtendedAttribute("LegacyLenientThis"):
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():
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
])
5945 attr
.value() != "Everything"
5946 and attr
.value() != "DOMState"
5947 and not self
.readonly
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
:
5958 "[UseCounter] must not be used on a stringifier attribute",
5959 [attr
.location
, self
.location
],
5961 elif identifier
== "Unscopable":
5962 if not attr
.noArguments():
5964 "[Unscopable] must take no arguments", [attr
.location
]
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():
5975 "[CEReactions] must take no arguments", [attr
.location
]
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
6005 "Unknown extended attribute %s on attribute" % identifier
,
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
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
6038 not self
.type.isDOMString()
6039 and not self
.type.isUSVString()
6040 and not self
.type.isUTF8String()
6043 "The type of a stringifer attribute must be "
6044 "either DOMString, USVString or UTF8String",
6047 identifier
= IDLUnresolvedIdentifier(
6048 self
.location
, "__stringifier", allowDoubleUnderscore
=True
6053 returnType
=self
.type,
6056 underlyingAttr
=self
,
6058 allowedExtAttrs
= ["Throws", "NeedsSubjectPrincipal", "Pure"]
6059 # Safe to ignore these as they are only meaningful for attributes
6060 attributeOnlyExtAttrs
= [
6062 "CrossOriginWritable",
6065 for key
, value
in self
._extendedAttrDict
.items():
6066 if key
in allowedExtAttrs
:
6067 if value
is not True:
6069 "[%s] with a value is currently "
6070 "unsupported in stringifier attributes, "
6071 "please file a bug to add support" % key
,
6074 method
.addExtendedAttributes(
6075 [IDLExtendedAttribute(self
.location
, (key
,))]
6077 elif key
not in attributeOnlyExtAttrs
:
6079 "[%s] is currently unsupported in "
6080 "stringifier attributes, please file a bug "
6081 "to add support" % key
,
6084 members
.append(method
)
6087 class IDLArgument(IDLObjectWithIdentifier
):
6095 "_allowTreatNonCallableAsNull",
6096 "_extendedAttrDict",
6097 "allowTypeAttributes",
6108 dictionaryMember
=False,
6109 allowTypeAttributes
=False,
6111 IDLObjectWithIdentifier
.__init
__(self
, location
, None, identifier
)
6113 assert isinstance(type, IDLType
)
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
:
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:
6155 "[%s] BinaryType must take one argument" % identifier
,
6156 [attribute
.location
],
6158 if not self
.defaultValue
:
6160 "[%s] BinaryType can't be used without default value"
6162 [attribute
.location
],
6166 "Unhandled extended attribute on %s"
6168 "a dictionary member"
6169 if self
.dictionaryMember
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
:
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
)
6196 if self
.type.isUndefined():
6198 "undefined must not be used as the type of an argument in any circumstance",
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
:
6214 "Dictionary members cannot be [LegacyNullToEmptyString]",
6217 if self
.type.isObservableArray():
6219 "%s cannot have an ObservableArray type"
6220 % ("Dictionary members" if self
.dictionaryMember
else "Arguments"),
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
)
6238 def canHaveMissingValue(self
):
6239 return self
.optional
and not self
.defaultValue
6242 class IDLCallback(IDLObjectWithScope
):
6246 "_treatNonCallableAsNull",
6247 "_treatNonObjectAsNull",
6248 "_isRunScriptBoundary",
6253 self
, location
, parentScope
, identifier
, returnType
, arguments
, isConstructor
6255 assert isinstance(returnType
, IDLType
)
6257 self
._returnType
= returnType
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
):
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():
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
6302 for argument
in self
._arguments
:
6303 if argument
.type.isUndefined():
6305 "undefined must not be used as the type of an argument in any circumstance",
6309 def addExtendedAttributes(self
, attrs
):
6312 if attr
.identifier() == "TreatNonCallableAsNull":
6313 self
._treatNonCallableAsNull
= True
6314 elif attr
.identifier() == "LegacyTreatNonObjectAsNull":
6315 if self
._isConstructor
:
6317 "[LegacyTreatNonObjectAsNull] is not supported "
6321 self
._treatNonObjectAsNull
= True
6322 elif attr
.identifier() == "MOZ_CAN_RUN_SCRIPT_BOUNDARY":
6323 if self
._isConstructor
:
6325 "[MOZ_CAN_RUN_SCRIPT_BOUNDARY] is not "
6326 "permitted on constructors",
6329 self
._isRunScriptBoundary
= True
6331 unhandledAttrs
.append(attr
)
6332 if self
._treatNonCallableAsNull
and self
._treatNonObjectAsNull
:
6334 "Cannot specify both [TreatNonCallableAsNull] "
6335 "and [LegacyTreatNonObjectAsNull]",
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
):
6359 return IDLType
.Tags
.callback
6361 def isDistinguishableFrom(self
, other
):
6362 if other
.isPromise():
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
6372 or other
.isPrimitive()
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
)
6406 def includesRestrictedFloatArgument(self
):
6407 return any(arg
.type.includesRestrictedFloat() for arg
in self
.arguments
)
6410 class IDLMethod(IDLInterfaceMember
, IDLScope
):
6412 "Getter", "Setter", "Deleter", "LegacyCaller", base
=IDLInterfaceMember
.Special
6415 NamedOrIndexed
= enum("Neither", "Named", "Indexed")
6426 "maplikeOrSetlikeOrIterable",
6430 "_legacyUnforgeable",
6446 specialType
=NamedOrIndexed
.Neither
,
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"
6488 if static
and identifier
.name
== "prototype":
6490 "The identifier of a static operation must not be 'prototype'",
6494 self
.assertSignatureConstraints()
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
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()
6513 assert len(self
._overloads
) == 1
6514 arguments
= self
._overloads
[0].arguments
6515 assert len(arguments
) == 2
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
:
6529 overload
.returnType
== BuiltinTypes
[IDLBuiltinType
.Types
.domstring
]
6535 def forceStatic(self
):
6544 def isDeleter(self
):
6545 return self
._deleter
6549 self
._specialType
== IDLMethod
.NamedOrIndexed
.Named
6550 or self
._specialType
== IDLMethod
.NamedOrIndexed
.Indexed
6552 return self
._specialType
== IDLMethod
.NamedOrIndexed
.Named
6554 def isIndexed(self
):
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
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
):
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.
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():
6629 "Restricted float behavior differs on different "
6630 "overloads of %s" % method
.identifier
,
6631 [overload
.location
, method
.location
],
6633 self
._extendedAttrDict
["LenientFloat"] = method
._extendedAttrDict
[
6636 elif method
._overloads
[0].includesRestrictedFloatArgument():
6638 "Restricted float behavior differs on different "
6639 "overloads of %s" % method
.identifier
,
6640 [self
.location
, method
.location
],
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():
6655 "Overloaded identifier %s appears with different values of the 'static' attribute"
6656 % method
.identifier
,
6660 if self
.isLegacycaller() != method
.isLegacycaller():
6663 "Overloaded identifier %s appears with different "
6664 "values of the 'legacycaller' attribute" % method
.identifier
6669 # Can't overload special things!
6672 or method
.isGetter()
6674 or method
.isSetter()
6676 or method
.isDeleter()
6677 or self
.isStringifier()
6678 or method
.isStringifier()
6681 ("Can't overload a special operation"),
6682 [self
.location
, method
.location
],
6684 if self
.isHTMLConstructor() or method
.isHTMLConstructor():
6687 "An interface must contain only a single operation annotated with HTMLConstructor, and no others"
6689 [self
.location
, method
.location
],
6694 def signatures(self
):
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
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:
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
:
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
,
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
):
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()
6770 argument
.type.isDictionary()
6771 and argument
.type.unroll().inner
.canBeEmpty()
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 :]
6783 "Dictionary argument without any "
6784 "required fields or union argument "
6785 "containing such dictionary not "
6786 "followed by a required argument "
6788 [argument
.location
],
6791 if not argument
.defaultValue
and all(
6792 arg
.optional
for arg
in arguments
[idx
+ 1 :]
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()
6808 argument
.type.isUnion()
6809 and argument
.type.unroll().hasDictionaryType()
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
:
6822 "Variadic argument is not last argument",
6823 [variadicArgument
.location
],
6825 if argument
.variadic
:
6826 variadicArgument
= argument
6828 if returnType
.isPromise():
6829 overloadWithPromiseReturnType
= overload
6831 overloadWithoutPromiseReturnType
= overload
6833 # Make sure either all our overloads return Promises or none do
6834 if overloadWithPromiseReturnType
and overloadWithoutPromiseReturnType
:
6836 "We have overloads with both Promise and non-Promise return types",
6838 overloadWithPromiseReturnType
.location
,
6839 overloadWithoutPromiseReturnType
.location
,
6843 if overloadWithPromiseReturnType
and self
._legacycaller
:
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()
6853 "StaticClassOverride can be applied to static"
6854 " methods on JS-implemented classes only.",
6858 # Ensure that toJSON methods satisfy the spec constraints on them.
6859 if self
.identifier
.name
== "toJSON":
6860 if len(self
.signatures()) != 1:
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():
6869 "toJSON method has non-JSON return type", [self
.location
]
6872 def overloadsForArgCount(self
, argc
):
6875 for overload
in self
._overloads
6876 if len(overload
.arguments
) == argc
6878 len(overload
.arguments
) > argc
6879 and all(arg
.optional
for arg
in overload
.arguments
[argc
:])
6882 len(overload
.arguments
) < argc
6883 and len(overload
.arguments
) > 0
6884 and overload
.arguments
[-1].variadic
6888 def signaturesForArgCount(self
, argc
):
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
6904 assert firstArgs
[-1].variadic
6905 firstType
= firstArgs
[-1].type
6906 if idx
< len(secondArgs
):
6907 secondType
= secondArgs
[idx
].type
6909 assert secondArgs
[-1].variadic
6910 secondType
= secondArgs
[-1].type
6911 if not firstType
.isDistinguishableFrom(secondType
):
6915 signatures
= self
.signaturesForArgCount(argc
)
6916 for idx
in range(argc
):
6917 if isValidDistinguishingIndex(idx
, signatures
):
6919 # No valid distinguishing index. Time to throw
6920 locations
= self
.locationsForArgCount(argc
)
6922 "Signatures with %d arguments for method '%s' are not "
6923 "distinguishable" % (argc
, self
.identifier
.name
),
6927 def handleExtendedAttribute(self
, attr
):
6928 identifier
= attr
.identifier()
6930 identifier
== "GetterThrows"
6931 or identifier
== "SetterThrows"
6932 or identifier
== "GetterCanOOM"
6933 or identifier
== "SetterCanOOM"
6934 or identifier
== "SetterNeedsSubjectPrincipal"
6935 or identifier
== "GetterNeedsSubjectPrincipal"
6938 "Methods must not be flagged as [%s]" % identifier
,
6939 [attr
.location
, self
.location
],
6941 elif identifier
== "LegacyUnforgeable":
6944 "[LegacyUnforgeable] is only allowed on non-static methods",
6945 [attr
.location
, self
.location
],
6947 self
._legacyUnforgeable
= True
6948 elif identifier
== "SameObject":
6950 "Methods must not be flagged as [SameObject]",
6951 [attr
.location
, self
.location
],
6953 elif identifier
== "Constant":
6955 "Methods must not be flagged as [Constant]",
6956 [attr
.location
, self
.location
],
6958 elif identifier
== "PutForwards":
6960 "Only attributes support [PutForwards]", [attr
.location
, self
.location
]
6962 elif identifier
== "LegacyLenientSetter":
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():
6973 "[LenientFloat] used on a non-undefined method",
6974 [attr
.location
, self
.location
],
6976 if not overloads
[0].includesRestrictedFloatArgument():
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
)
6985 identifier
== "CrossOriginCallable"
6986 or identifier
== "WebGLHandlesContextLoss"
6988 # Known no-argument attributes.
6989 if not attr
.noArguments():
6991 "[%s] must take no arguments" % identifier
, [attr
.location
]
6993 if identifier
== "CrossOriginCallable" and self
.isStatic():
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():
7014 "[Alias] takes an identifier or string", [attr
.location
]
7016 self
._addAlias
(attr
.value())
7017 elif identifier
== "UseCounter":
7018 if self
.isSpecial():
7020 "[UseCounter] must not be used on a special operation",
7021 [attr
.location
, self
.location
],
7023 elif identifier
== "Unscopable":
7024 if not attr
.noArguments():
7026 "[Unscopable] must take no arguments", [attr
.location
]
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():
7037 "[CEReactions] must take no arguments", [attr
.location
]
7040 if self
.isSpecial() and not self
.isSetter() and not self
.isDeleter():
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():
7052 "[Default] is only allowed on toJSON operations",
7053 [attr
.location
, self
.location
],
7056 if self
.signatures()[0][0] != BuiltinTypes
[IDLBuiltinType
.Types
.object]:
7058 "The return type of the default toJSON "
7059 "operation must be 'object'",
7060 [attr
.location
, self
.location
],
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
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
):
7096 for overload
in self
._overloads
:
7097 deps
.update(overload
._getDependentObjects
())
7101 class IDLConstructor(IDLMethod
):
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
7114 self
._initLocation
= location
7115 self
._initArgs
= args
7116 self
._initName
= name
7117 self
._inited
= False
7118 self
._initExtendedAttrs
= []
7120 def addExtendedAttributes(self
, attrs
):
7122 return IDLMethod
.addExtendedAttributes(self
, attrs
)
7123 self
._initExtendedAttrs
.extend(attrs
)
7125 def handleExtendedAttribute(self
, attr
):
7126 identifier
= attr
.identifier()
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():
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()):
7149 "[HTMLConstructor] must not be applied to a "
7150 "constructor operation that has arguments.",
7153 self
._htmlConstructor
= True
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
)
7165 self
, location
, identifier
, retType
, self
._initArgs
, static
=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
7185 self
._finished
= False
7187 def finish(self
, scope
):
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
7198 if not isinstance(interface
, IDLInterface
):
7200 "Left-hand side of 'includes' is not an interface",
7201 [self
.interface
.location
, interface
.location
],
7203 if interface
.isCallback():
7205 "Left-hand side of 'includes' is a callback interface",
7206 [self
.interface
.location
, interface
.location
],
7208 if not isinstance(mixin
, IDLInterfaceMixin
):
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
7223 def addExtendedAttributes(self
, attrs
):
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
)
7243 def identifier(self
):
7244 return self
._tuple
[0]
7246 def noArguments(self
):
7247 return len(self
._tuple
) == 1
7250 return len(self
._tuple
) >= 2 and isinstance(self
._tuple
[1], str)
7253 assert self
.hasValue()
7254 return self
._tuple
[1]
7258 len(self
._tuple
) == 2
7259 and isinstance(self
._tuple
[1], list)
7260 or len(self
._tuple
) == 3
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:]
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
)
7286 def t_INTEGER(self
, t
):
7287 r
"-?(0([0-7]+|[Xx][0-9A-Fa-f]+)?|[1-9][0-9]*)"
7289 # Can't use int(), because that doesn't handle octal properly.
7290 t
.value
= parseInt(t
.value
)
7293 "Invalid integer literal",
7297 lineno
=self
.lexer
.lineno
,
7298 lexpos
=self
.lexer
.lexpos
,
7299 filename
=self
._filename
,
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")
7310 def t_STRING(self
, t
):
7312 t
.value
= t
.value
[1:-1]
7315 t_ignore
= "\t\n\r "
7317 def t_COMMENTS(self
, t
):
7318 r
"//[^\n]*|/\*(?s:.)*?\*/"
7321 def t_ELLIPSIS(self
, t
):
7326 def t_OTHER(self
, t
):
7328 t
.type = self
.keywords
.get(t
.value
, "OTHER")
7332 "interface": "INTERFACE",
7333 "partial": "PARTIAL",
7335 "dictionary": "DICTIONARY",
7336 "exception": "EXCEPTION",
7338 "callback": "CALLBACK",
7339 "typedef": "TYPEDEF",
7340 "includes": "INCLUDES",
7345 "serializer": "SERIALIZER",
7346 "stringifier": "STRINGIFIER",
7347 "unrestricted": "UNRESTRICTED",
7348 "attribute": "ATTRIBUTE",
7349 "readonly": "READONLY",
7350 "inherit": "INHERIT",
7354 "deleter": "DELETER",
7355 "legacycaller": "LEGACYCALLER",
7356 "optional": "OPTIONAL",
7359 "DOMString": "DOMSTRING",
7360 "ByteString": "BYTESTRING",
7361 "USVString": "USVSTRING",
7362 "JSString": "JSSTRING",
7363 "UTF8String": "UTF8STRING",
7365 "boolean": "BOOLEAN",
7371 "ObservableArray": "OBSERVABLEARRAY",
7373 "Promise": "PROMISE",
7374 "required": "REQUIRED",
7375 "sequence": "SEQUENCE",
7378 "unsigned": "UNSIGNED",
7379 "undefined": "UNDEFINED",
7388 "?": "QUESTIONMARK",
7394 "ArrayBuffer": "ARRAYBUFFER",
7396 "maplike": "MAPLIKE",
7397 "setlike": "SETLIKE",
7398 "iterable": "ITERABLE",
7399 "namespace": "NAMESPACE",
7400 "constructor": "CONSTRUCTOR",
7405 tokens
.extend(keywords
.values())
7407 def t_error(self
, t
):
7409 "Unrecognized Input",
7413 lineno
=self
.lexer
.lineno
,
7414 lexpos
=self
.lexer
.lexpos
,
7415 filename
=self
._filename
,
7420 def __init__(self
, outputdir
, lexer
=None):
7424 self
.lexer
= lex
.lex(object=self
)
7427 class SqueakyCleanLogger(object):
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",
7448 def debug(self
, msg
, *args
, **kwargs
):
7453 def warning(self
, msg
, *args
, **kwargs
):
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:]
7464 whitelistargs
= args
7465 if (whitelistmsg
% whitelistargs
) not in SqueakyCleanLogger
.errorWhitelist
:
7466 self
.errors
.append(msg
% args
)
7470 def reportGrammarErrors(self
):
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
7490 p
[2].addExtendedAttributes(p
[1])
7497 def p_DefinitionsEmpty(self
, p
):
7503 def p_Definition(self
, p
):
7505 Definition : CallbackOrInterfaceOrMixin
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)
7527 def p_CallbackOrInterfaceOrMixinInterfaceOrMixin(self
, p
):
7529 CallbackOrInterfaceOrMixin : INTERFACE InterfaceOrMixin
7533 def p_CallbackRestOrInterface(self
, p
):
7535 CallbackRestOrInterface : CallbackRest
7536 | CallbackConstructorRest
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
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
7559 prettyname
= constructor
.__name
__[3:].lower()
7562 existingObj
= self
.globalScope()._lookupIdentifier
(identifier
)
7564 if not isinstance(existingObj
, constructor
):
7566 "%s has the same name as "
7567 "non-%s object" % (prettyname
.capitalize(), prettyname
),
7568 [location
, existingObj
.location
],
7570 existingObj
.setNonPartial(*nonPartialArgs
)
7572 except Exception as ex
:
7573 if isinstance(ex
, WebIDLError
):
7577 # True for isKnownNonPartial
7578 return constructor(*(constructorArgs
+ [True]))
7580 def p_InterfaceOrMixin(self
, p
):
7582 InterfaceOrMixin : InterfaceRest
7587 def p_CallbackInterface(self
, p
):
7589 CallbackInterface : INTERFACE InterfaceRest
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])
7602 p
[0] = self
.handleNonPartialObject(
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])
7618 if self
.globalScope()._lookupIdentifier
(identifier
):
7619 p
[0] = self
.globalScope()._lookupIdentifier
(identifier
)
7620 if not isinstance(p
[0], IDLExternalInterface
):
7622 "Name collision between external "
7623 "interface declaration for identifier "
7624 "%s and %s" % (identifier
.name
, p
[0]),
7625 [location
, p
[0].location
],
7628 except Exception as ex
:
7629 if isinstance(ex
, WebIDLError
):
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])
7643 p
[0] = self
.handleNonPartialObject(
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])
7659 p
[0] = self
.handleNonPartialObject(
7663 [location
, self
.globalScope(), identifier
, members
],
7664 [location
, None, members
],
7667 def p_Partial(self
, p
):
7669 Partial : PARTIAL PartialDefinition
7673 def p_PartialDefinitionInterface(self
, p
):
7675 PartialDefinition : INTERFACE PartialInterfaceOrPartialMixin
7679 def p_PartialDefinition(self
, p
):
7681 PartialDefinition : PartialNamespace
7686 def handlePartialObject(
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
7710 prettyname
= nonPartialConstructor
.__name
__[3:].lower()
7712 nonPartialObject
= None
7714 nonPartialObject
= self
.globalScope()._lookupIdentifier
(identifier
)
7715 if nonPartialObject
:
7716 if not isinstance(nonPartialObject
, nonPartialConstructor
):
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
):
7727 if not nonPartialObject
:
7728 nonPartialObject
= nonPartialConstructor(
7729 # No members, False for isKnownNonPartial
7730 *(nonPartialConstructorArgs
),
7732 isKnownNonPartial
=False
7735 partialObject
= None
7736 if isinstance(nonPartialObject
, IDLDictionary
):
7737 partialObject
= IDLPartialDictionary(
7738 *(partialConstructorArgs
+ [nonPartialObject
])
7741 nonPartialObject
, (IDLInterface
, IDLInterfaceMixin
, IDLNamespace
)
7743 partialObject
= IDLPartialInterfaceOrNamespace(
7744 *(partialConstructorArgs
+ [nonPartialObject
])
7748 "Unknown partial object type %s" % type(partialObject
), [location
]
7751 return partialObject
7753 def p_PartialInterfaceOrPartialMixin(self
, p
):
7755 PartialInterfaceOrPartialMixin : PartialInterfaceRest
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])
7768 p
[0] = self
.handlePartialObject(
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])
7784 p
[0] = self
.handlePartialObject(
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])
7800 p
[0] = self
.handlePartialObject(
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])
7816 p
[0] = self
.handlePartialObject(
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
):
7836 def p_InterfaceMembers(self
, p
):
7838 InterfaceMembers : ExtendedAttributeList InterfaceMember InterfaceMembers
7842 assert not p
[1] or p
[2]
7843 p
[2].addExtendedAttributes(p
[1])
7847 def p_InterfaceMembersEmpty(self
, p
):
7853 def p_InterfaceMember(self
, p
):
7855 InterfaceMember : PartialInterfaceMember
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
7872 assert not p
[1] or p
[2]
7873 p
[2].addExtendedAttributes(p
[1])
7877 def p_PartialInterfaceMembersEmpty(self
, p
):
7879 PartialInterfaceMembers :
7883 def p_PartialInterfaceMember(self
, p
):
7885 PartialInterfaceMember : Const
7886 | AttributeOrOperationOrMaplikeOrSetlikeOrIterable
7890 def p_MixinMembersEmpty(self
, p
):
7896 def p_MixinMembers(self
, p
):
7898 MixinMembers : ExtendedAttributeList MixinMember MixinMembers
7902 assert not p
[1] or p
[2]
7903 p
[2].addExtendedAttributes(p
[1])
7907 def p_MixinMember(self
, p
):
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])
7922 p
[0] = IDLDictionary(location
, self
.globalScope(), identifier
, p
[3], members
)
7924 def p_DictionaryMembers(self
, p
):
7926 DictionaryMembers : ExtendedAttributeList DictionaryMember DictionaryMembers
7930 # We're at the end of the list
7933 p
[2].addExtendedAttributes(p
[1])
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.
7943 assert isinstance(t
, IDLType
)
7944 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 3), p
[3])
7947 self
.getLocation(p
, 3),
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.
7962 assert isinstance(t
, IDLType
)
7963 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 2), p
[2])
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
7970 self
.getLocation(p
, 2),
7974 defaultValue
=defaultValue
,
7976 dictionaryMember
=True,
7977 allowTypeAttributes
=True,
7980 def p_Default(self
, p
):
7982 Default : EQUALS DefaultValue
7990 def p_DefaultValue(self
, p
):
7992 DefaultValue : ConstValue
7999 assert len(p
) == 3 # Must be [] or {}
8001 p
[0] = IDLEmptySequenceValue(self
.getLocation(p
, 1))
8004 p
[0] = IDLDefaultDictionaryValue(self
.getLocation(p
, 1))
8006 def p_DefaultValueNull(self
, p
):
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
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])
8033 p
[0] = IDLEnum(location
, self
.globalScope(), identifier
, values
)
8035 def p_EnumValueList(self
, p
):
8037 EnumValueList : STRING EnumValueListComma
8042 def p_EnumValueListComma(self
, p
):
8044 EnumValueListComma : COMMA EnumValueListString
8048 def p_EnumValueListCommaEmpty(self
, p
):
8050 EnumValueListComma :
8054 def p_EnumValueListString(self
, p
):
8056 EnumValueListString : STRING EnumValueListComma
8061 def p_EnumValueListStringEmpty(self
, p
):
8063 EnumValueListString :
8067 def p_CallbackRest(self
, p
):
8069 CallbackRest : IDENTIFIER EQUALS Type LPAREN ArgumentList RPAREN SEMICOLON
8071 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 1), p
[1])
8073 self
.getLocation(p
, 1),
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])
8087 self
.getLocation(p
, 2),
8095 def p_ExceptionMembers(self
, p
):
8097 ExceptionMembers : ExtendedAttributeList ExceptionMember ExceptionMembers
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),
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)
8130 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 3), p
[3])
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)
8162 location
, BuiltinTypes
[IDLBuiltinType
.Types
.unrestricted_float
], p
[1]
8165 def p_ConstValueString(self
, p
):
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
8179 def p_BooleanLiteralFalse(self
, p
):
8181 BooleanLiteral : FALSE
8185 def p_AttributeOrOperationOrMaplikeOrSetlikeOrIterable(self
, p
):
8187 AttributeOrOperationOrMaplikeOrSetlikeOrIterable : Attribute
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
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
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
8251 maplikeOrSetlikeType
= p
[2]
8252 location
= self
.getLocation(p
, 2)
8253 identifier
= IDLUnresolvedIdentifier(
8254 location
, "__setlike", allowDoubleUnderscore
=True
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
8267 maplikeOrSetlikeType
= p
[2]
8268 location
= self
.getLocation(p
, 2)
8269 identifier
= IDLUnresolvedIdentifier(
8270 location
, "__maplike", allowDoubleUnderscore
=True
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)
8310 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 4), p
[4])
8311 p
[0] = (location
, identifier
, t
, readonly
)
8313 def p_ReadOnly(self
, p
):
8319 def p_ReadOnlyEmpty(self
, p
):
8325 def p_Operation(self
, p
):
8327 Operation : Qualifiers OperationRest
8331 # Disallow duplicates in the qualifier set
8332 if not len(set(qualifiers
)) == len(qualifiers
):
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
:
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:
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
8379 "There is no such thing as an indexed deleter.",
8380 [self
.getLocation(p
, 1)],
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
:
8390 "%s cannot have %s argument"
8392 "getter" if getter
else "deleter",
8393 "optional" if arguments
[0].optional
else "variadic",
8395 [arguments
[0].location
],
8398 if returnType
.isUndefined():
8400 "getter cannot have undefined return type", [self
.getLocation(p
, 2)]
8403 if len(arguments
) != 2:
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
8414 "settter has wrong argument type (must be DOMString or UnsignedLong)",
8415 [arguments
[0].location
],
8417 if arguments
[0].optional
or arguments
[0].variadic
:
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
:
8425 "setter cannot have %s argument"
8426 % ("optional" if arguments
[1].optional
else "variadic"),
8427 [arguments
[1].location
],
8431 if len(arguments
) != 0:
8433 "stringifier has wrong number of arguments",
8434 [self
.getLocation(p
, 2)],
8436 if not returnType
.isDOMString():
8438 "stringifier must have DOMString return type",
8439 [self
.getLocation(p
, 2)],
8442 # identifier might be None. This is only permitted for special methods.
8448 and not legacycaller
8452 "Identifier required for non-special methods",
8453 [self
.getLocation(p
, 2)],
8456 location
= BuiltinLocation("<auto-generated-identifier>")
8457 identifier
= IDLUnresolvedIdentifier(
8463 if specialType
== IDLMethod
.NamedOrIndexed
.Named
8466 if specialType
== IDLMethod
.NamedOrIndexed
.Indexed
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,
8480 self
.getLocation(p
, 2),
8488 specialType
=specialType
,
8489 legacycaller
=legacycaller
,
8490 stringifier
=stringifier
,
8494 def p_Stringifier(self
, p
):
8496 Operation : STRINGIFIER SEMICOLON
8498 identifier
= IDLUnresolvedIdentifier(
8499 BuiltinLocation("<auto-generated-identifier>"),
8501 allowDoubleUnderscore
=True,
8504 self
.getLocation(p
, 1),
8506 returnType
=BuiltinTypes
[IDLBuiltinType
.Types
.domstring
],
8512 def p_QualifierStatic(self
, p
):
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
8531 def p_Specials(self
, p
):
8533 Specials : Special Specials
8538 def p_SpecialsEmpty(self
, p
):
8544 def p_SpecialGetter(self
, p
):
8548 p
[0] = IDLMethod
.Special
.Getter
8550 def p_SpecialSetter(self
, p
):
8554 p
[0] = IDLMethod
.Special
.Setter
8556 def p_SpecialDeleter(self
, p
):
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 :
8586 def p_ArgumentList(self
, p
):
8588 ArgumentList : Argument Arguments
8590 p
[0] = [p
[1]] if p
[1] else []
8593 def p_ArgumentListEmpty(self
, p
):
8599 def p_Arguments(self
, p
):
8601 Arguments : COMMA Argument Arguments
8603 p
[0] = [p
[2]] if p
[2] else []
8606 def p_ArgumentsEmpty(self
, p
):
8612 def p_Argument(self
, p
):
8614 Argument : ExtendedAttributeList ArgumentRest
8617 p
[0].addExtendedAttributes(p
[1])
8619 def p_ArgumentRestOptional(self
, p
):
8621 ArgumentRest : OPTIONAL TypeWithExtendedAttributes ArgumentName Default
8624 assert isinstance(t
, IDLType
)
8625 # Arg names can be reserved identifiers
8626 identifier
= IDLUnresolvedIdentifier(
8627 self
.getLocation(p
, 3), p
[3], allowForbidden
=True
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.
8637 self
.getLocation(p
, 3), identifier
, t
, True, defaultValue
, False
8640 def p_ArgumentRest(self
, p
):
8642 ArgumentRest : Type Ellipsis ArgumentName
8645 assert isinstance(t
, IDLType
)
8646 # Arg names can be reserved identifiers
8647 identifier
= IDLUnresolvedIdentifier(
8648 self
.getLocation(p
, 3), p
[3], allowForbidden
=True
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
8662 self
.getLocation(p
, 3),
8668 allowTypeAttributes
=True,
8671 def p_ArgumentName(self
, p
):
8673 ArgumentName : IDENTIFIER
8674 | ArgumentNameKeyword
8678 def p_ArgumentNameKeyword(self
, p
):
8680 ArgumentNameKeyword : ASYNC
8711 def p_AttributeName(self
, p
):
8713 AttributeName : IDENTIFIER
8714 | AttributeNameKeyword
8718 def p_AttributeNameKeyword(self
, p
):
8720 AttributeNameKeyword : ASYNC
8725 def p_Ellipsis(self
, p
):
8731 def p_EllipsisEmpty(self
, p
):
8737 def p_ExceptionMember(self
, p
):
8739 ExceptionMember : Const
8744 def p_ExceptionField(self
, p
):
8746 ExceptionField : Type IDENTIFIER SEMICOLON
8750 def p_ExtendedAttributeList(self
, p
):
8752 ExtendedAttributeList : LBRACKET ExtendedAttribute ExtendedAttributes RBRACKET
8758 def p_ExtendedAttributeListEmpty(self
, p
):
8760 ExtendedAttributeList :
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
):
8781 def p_ExtendedAttributes(self
, p
):
8783 ExtendedAttributes : COMMA ExtendedAttribute ExtendedAttributes
8785 p
[0] = [p
[2]] if p
[2] else []
8788 def p_ExtendedAttributesEmpty(self
, p
):
8790 ExtendedAttributes :
8794 def p_Other(self
, p
):
8835 | ArgumentNameKeyword
8839 def p_OtherOrComma(self
, p
):
8841 OtherOrComma : Other
8846 def p_TypeSingleType(self
, p
):
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
8870 def p_SingleTypeAnyType(self
, p
):
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]]
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
8909 def p_UnionMemberTypesEmpty(self
, p
):
8915 def p_DistinguishableType(self
, p
):
8917 DistinguishableType : PrimitiveType 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
]
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
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
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
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":
8972 "Promise used without saying what it's parametrized over",
8973 [self
.getLocation(p
, 1)],
8979 if self
.globalScope()._lookupIdentifier
(p
[1]):
8980 obj
= self
.globalScope()._lookupIdentifier
(p
[1])
8981 assert not obj
.isType()
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
)
8989 type = IDLWrapperType(self
.getLocation(p
, 1), p
[1])
8990 p
[0] = self
.handleNullable(type, p
[2])
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
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:
9103 def p_UnsignedIntegerType(self
, p
):
9105 UnsignedIntegerType : IntegerType
9109 def p_IntegerTypeShort(self
, p
):
9113 p
[0] = IDLBuiltinType
.Types
.short
9115 def p_IntegerTypeLong(self
, p
):
9117 IntegerType : LONG OptionalLong
9120 p
[0] = IDLBuiltinType
.Types
.long_long
9122 p
[0] = IDLBuiltinType
.Types
.long
9124 def p_OptionalLong(self
, p
):
9130 def p_OptionalLongEmpty(self
, p
):
9136 def p_Null(self
, p
):
9142 p
[0] = self
.getLocation(p
, 1)
9146 def p_ScopedName(self
, p
):
9148 ScopedName : AbsoluteScopedName
9149 | RelativeScopedName
9153 def p_AbsoluteScopedName(self
, p
):
9155 AbsoluteScopedName : SCOPE IDENTIFIER ScopedNameParts
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
9175 def p_ScopedNamePartsEmpty(self
, p
):
9181 def p_ExtendedAttributeNoArgs(self
, p
):
9183 ExtendedAttributeNoArgs : IDENTIFIER
9187 def p_ExtendedAttributeArgList(self
, p
):
9189 ExtendedAttributeArgList : IDENTIFIER LPAREN ArgumentList RPAREN
9193 def p_ExtendedAttributeIdent(self
, p
):
9195 ExtendedAttributeIdent : IDENTIFIER EQUALS STRING
9196 | IDENTIFIER EQUALS IDENTIFIER
9200 def p_ExtendedAttributeWildcard(self
, p
):
9202 ExtendedAttributeWildcard : IDENTIFIER EQUALS ASTERISK
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
9218 def p_IdentifierList(self
, p
):
9220 IdentifierList : IDENTIFIER Identifiers
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.
9229 idents
.insert(0, ident
)
9232 def p_IdentifiersList(self
, p
):
9234 Identifiers : COMMA IDENTIFIER Identifiers
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.
9243 idents
.insert(0, ident
)
9246 def p_IdentifiersEmpty(self
, p
):
9252 def p_error(self
, p
):
9256 "Syntax Error at end of file. Possibly due to "
9257 "missing semicolon(;), braces(}) or both"
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()
9272 self
.parser
= yacc
.yacc(
9274 outputdir
=outputdir
,
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'
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.
9302 IDLBuiltinType
.Types
.ArrayBuffer
, IDLBuiltinType
.Types
.Float64Array
+ 1
9304 builtin
= BuiltinTypes
[x
]
9305 identifier
= IDLUnresolvedIdentifier(
9306 BuiltinLocation("<builtin type>"), builtin
.name
9309 BuiltinLocation("<builtin type>"),
9316 def handleNullable(type, questionMarkLocation
):
9317 if questionMarkLocation
is not None:
9318 type = IDLNullableType(questionMarkLocation
, type)
9322 def parse(self
, t
, filename
=None):
9325 # for tok in iter(self.lexer.token, None):
9328 self
._filename
= filename
9329 self
._productions
.extend(self
.parser
.parse(lexer
=self
.lexer
, tracking
=True))
9330 self
._filename
= None
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
:
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
9346 for m
in iface
.members
:
9347 if isinstance(m
, (IDLIterable
, IDLAsyncIterable
)):
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
]
9360 nextReturnType
= BuiltinTypes
[IDLBuiltinType
.Types
.object]
9361 nextMethod
= IDLMethod(
9363 IDLUnresolvedIdentifier(iterable
.location
, "next"),
9367 nextMethod
.addExtendedAttributes([simpleExtendedAttr("Throws")])
9369 methods
= [nextMethod
]
9371 if iterable
.getExtendedAttribute("GenerateReturnMethod"):
9372 assert isinstance(iterable
, IDLAsyncIterable
)
9374 returnMethod
= IDLMethod(
9376 IDLUnresolvedIdentifier(iterable
.location
, "return"),
9378 iterable
.location
, BuiltinTypes
[IDLBuiltinType
.Types
.any
]
9383 IDLUnresolvedIdentifier(
9384 BuiltinLocation("<auto-generated-identifier>"),
9387 BuiltinTypes
[IDLBuiltinType
.Types
.any
],
9392 returnMethod
.addExtendedAttributes([simpleExtendedAttr("Throws")])
9393 methods
.append(returnMethod
)
9395 if iterable
.isIterable():
9396 itr_suffix
= "Iterator"
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(
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
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
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
)
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())
9456 return Parser(lexer
=self
.lexer
)
9458 # Builtin IDL defined by WebIDL
9460 typedef (ArrayBufferView or ArrayBuffer) BufferSource;
9466 from optparse
import OptionParser
9468 usageString
= "usage: %prog [options] files"
9469 o
= OptionParser(usage
=usageString
)
9474 help="Directory in which to cache lex/parse tables.",
9478 action
="store_true",
9480 help="When an error happens, display the Python traceback.",
9482 (options
, args
) = o
.parse_args()
9485 o
.error(usageString
)
9488 baseDir
= os
.getcwd()
9491 parser
= Parser(options
.cachedir
)
9493 for filename
in fileList
:
9494 fullPath
= os
.path
.normpath(os
.path
.join(baseDir
, filename
))
9495 f
= open(fullPath
, "rb")
9496 lines
= f
.readlines()
9499 parser
.parse("".join(lines
), fullPath
)
9501 except WebIDLError
as e
:
9502 if options
.verbose_errors
:
9503 traceback
.print_exc()
9508 if __name__
== "__main__":