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 def enum(*names
, **kw
):
50 def __init__(self
, names
):
51 for v
, k
in enumerate(names
):
54 def __getattr__(self
, attr
):
55 if attr
in self
.attrs
:
56 return self
.attrs
[attr
]
59 def __setattr__(self
, name
, value
): # this makes it read-only
60 raise NotImplementedError
64 return Foo(chain(kw
["base"].attrs
.keys(), names
))
67 class WebIDLError(Exception):
68 def __init__(self
, message
, locations
, warning
=False):
69 self
.message
= message
70 self
.locations
= [str(loc
) for loc
in locations
]
71 self
.warning
= warning
74 return "%s: %s%s%s" % (
75 self
.warning
and "warning" or "error",
77 ", " if len(self
.locations
) != 0 else "",
78 "\n".join(self
.locations
),
82 class Location(object):
83 def __init__(self
, lexer
, lineno
, lexpos
, filename
):
87 self
._lexdata
= lexer
.lexdata
88 self
._file
= filename
if filename
else "<unknown>"
90 def __eq__(self
, other
):
91 return self
._lexpos
== other
._lexpos
and self
._file
== other
._file
100 startofline
= self
._lexdata
.rfind("\n", 0, self
._lexpos
) + 1
101 endofline
= self
._lexdata
.find("\n", self
._lexpos
, self
._lexpos
+ 80)
103 self
._line
= self
._lexdata
[startofline
:endofline
]
105 self
._line
= self
._lexdata
[startofline
:]
106 self
._colno
= self
._lexpos
- startofline
108 # Our line number seems to point to the start of self._lexdata
109 self
._lineno
+= self
._lexdata
.count("\n", 0, startofline
)
113 return "%s line %s:%s" % (self
._file
, self
._lineno
, self
._colno
)
115 def _pointerline(self
):
116 return " " * self
._colno
+ "^"
120 return "%s line %s:%s\n%s\n%s" % (
129 class BuiltinLocation(object):
130 def __init__(self
, text
):
131 self
.msg
= text
+ "\n"
133 def __eq__(self
, other
):
134 return isinstance(other
, BuiltinLocation
) and self
.msg
== other
.msg
152 class IDLObject(object):
153 def __init__(self
, location
):
154 self
.location
= location
155 self
.userData
= dict()
158 return self
.location
.filename()
160 def isInterface(self
):
163 def isNamespace(self
):
166 def isInterfaceMixin(self
):
172 def isCallback(self
):
178 def isDictionary(self
):
187 def getUserData(self
, key
, default
):
188 return self
.userData
.get(key
, default
)
190 def setUserData(self
, key
, value
):
191 self
.userData
[key
] = value
193 def addExtendedAttributes(self
, attrs
):
194 assert False # Override me!
196 def handleExtendedAttribute(self
, attr
):
197 assert False # Override me!
199 def _getDependentObjects(self
):
200 assert False # Override me!
202 def getDeps(self
, visited
=None):
203 """Return a set of files that this object depends on. If any of
204 these files are changed the parser needs to be rerun to regenerate
207 The visited argument is a set of all the objects already visited.
208 We must test to see if we are in it, and if so, do nothing. This
209 prevents infinite recursion."""
211 # NB: We can't use visited=set() above because the default value is
212 # evaluated when the def statement is evaluated, not when the function
213 # is executed, so there would be one set for all invocations.
223 if self
.filename() != "<builtin>":
224 deps
.add(self
.filename())
226 for d
in self
._getDependentObjects
():
227 deps
.update(d
.getDeps(visited
))
232 class IDLScope(IDLObject
):
233 def __init__(self
, location
, parentScope
, identifier
):
234 IDLObject
.__init
__(self
, location
)
236 self
.parentScope
= parentScope
238 assert isinstance(identifier
, IDLIdentifier
)
239 self
._name
= identifier
244 self
.globalNames
= set()
245 # A mapping from global name to the set of global interfaces
246 # that have that global name.
247 self
.globalNameMapping
= defaultdict(set)
253 # It's possible for us to be called before __init__ has been called, for
254 # the IDLObjectWithScope case. In that case, self._name won't be set yet.
255 if hasattr(self
, "_name"):
260 return name
.QName() + "::"
263 def ensureUnique(self
, identifier
, object):
265 Ensure that there is at most one 'identifier' in scope ('self').
266 Note that object can be None. This occurs if we end up here for an
267 interface type we haven't seen yet.
269 assert isinstance(identifier
, IDLUnresolvedIdentifier
)
270 assert not object or isinstance(object, IDLObjectWithIdentifier
)
271 assert not object or object.identifier
== identifier
273 if identifier
.name
in self
._dict
:
277 # ensureUnique twice with the same object is not allowed
278 assert id(object) != id(self
._dict
[identifier
.name
])
280 replacement
= self
.resolveIdentifierConflict(
281 self
, identifier
, self
._dict
[identifier
.name
], object
283 self
._dict
[identifier
.name
] = replacement
286 self
.addNewIdentifier(identifier
, object)
288 def addNewIdentifier(self
, identifier
, object):
291 self
._dict
[identifier
.name
] = object
293 def resolveIdentifierConflict(self
, scope
, identifier
, originalObject
, newObject
):
295 isinstance(originalObject
, IDLExternalInterface
)
296 and isinstance(newObject
, IDLExternalInterface
)
297 and originalObject
.identifier
.name
== newObject
.identifier
.name
299 return originalObject
301 if isinstance(originalObject
, IDLExternalInterface
) or isinstance(
302 newObject
, IDLExternalInterface
305 "Name collision between "
306 "interface declarations for identifier '%s' at '%s' and '%s'"
307 % (identifier
.name
, originalObject
.location
, newObject
.location
),
311 if isinstance(originalObject
, IDLDictionary
) or isinstance(
312 newObject
, IDLDictionary
315 "Name collision between dictionary declarations for "
316 "identifier '%s'.\n%s\n%s"
317 % (identifier
.name
, originalObject
.location
, newObject
.location
),
321 # We do the merging of overloads here as opposed to in IDLInterface
322 # because we need to merge overloads of LegacyFactoryFunctions and we need to
323 # detect conflicts in those across interfaces. See also the comment in
324 # IDLInterface.addExtendedAttributes for "LegacyFactoryFunction".
325 if isinstance(originalObject
, IDLMethod
) and isinstance(newObject
, IDLMethod
):
326 return originalObject
.addOverload(newObject
)
328 # Default to throwing, derived classes can override.
329 raise self
.createIdentifierConflictError(identifier
, originalObject
, newObject
)
331 def createIdentifierConflictError(self
, identifier
, originalObject
, newObject
):
332 conflictdesc
= "\n\t%s at %s\n\t%s at %s" % (
334 originalObject
.location
,
340 "Multiple unresolvable definitions of identifier '%s' in scope '%s'%s"
341 % (identifier
.name
, str(self
), conflictdesc
),
345 def _lookupIdentifier(self
, identifier
):
346 return self
._dict
[identifier
.name
]
348 def lookupIdentifier(self
, identifier
):
349 assert isinstance(identifier
, IDLIdentifier
)
350 assert identifier
.scope
== self
351 return self
._lookupIdentifier
(identifier
)
353 def addIfaceGlobalNames(self
, interfaceName
, globalNames
):
354 """Record the global names (from |globalNames|) that can be used in
355 [Exposed] to expose things in a global named |interfaceName|"""
356 self
.globalNames
.update(globalNames
)
357 for name
in globalNames
:
358 self
.globalNameMapping
[name
].add(interfaceName
)
361 class IDLIdentifier(IDLObject
):
362 def __init__(self
, location
, scope
, name
):
363 IDLObject
.__init
__(self
, location
)
366 assert isinstance(scope
, IDLScope
)
373 return self
.scope
.QName() + self
.name
376 return self
.QName().__hash
__()
378 def __eq__(self
, other
):
379 return self
.QName() == other
.QName()
382 return self
.scope
.lookupIdentifier(self
)
385 class IDLUnresolvedIdentifier(IDLObject
):
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 def __init__(self
, location
, parentScope
, identifier
):
431 IDLObject
.__init
__(self
, location
)
433 assert isinstance(identifier
, IDLUnresolvedIdentifier
)
435 self
.identifier
= identifier
438 self
.resolve(parentScope
)
440 def resolve(self
, parentScope
):
441 assert isinstance(parentScope
, IDLScope
)
442 assert isinstance(self
.identifier
, IDLUnresolvedIdentifier
)
443 self
.identifier
.resolve(parentScope
, self
)
446 class IDLObjectWithScope(IDLObjectWithIdentifier
, IDLScope
):
447 def __init__(self
, location
, parentScope
, identifier
):
448 assert isinstance(identifier
, IDLUnresolvedIdentifier
)
450 IDLObjectWithIdentifier
.__init
__(self
, location
, parentScope
, identifier
)
451 IDLScope
.__init
__(self
, location
, parentScope
, self
.identifier
)
454 class IDLIdentifierPlaceholder(IDLObjectWithIdentifier
):
455 def __init__(self
, location
, identifier
):
456 assert isinstance(identifier
, IDLUnresolvedIdentifier
)
457 IDLObjectWithIdentifier
.__init
__(self
, location
, None, identifier
)
459 def finish(self
, scope
):
461 scope
._lookupIdentifier
(self
.identifier
)
464 "Unresolved type '%s'." % self
.identifier
, [self
.location
]
467 obj
= self
.identifier
.resolve(scope
, None)
468 return scope
.lookupIdentifier(obj
)
471 class IDLExposureMixins
:
472 def __init__(self
, location
):
473 # _exposureGlobalNames are the global names listed in our [Exposed]
474 # extended attribute. exposureSet is the exposure set as defined in the
475 # Web IDL spec: it contains interface names.
476 self
._exposureGlobalNames
= set()
477 self
.exposureSet
= set()
478 self
._location
= location
479 self
._globalScope
= None
481 def finish(self
, scope
):
482 assert scope
.parentScope
is None
483 self
._globalScope
= scope
485 if "*" in self
._exposureGlobalNames
:
486 self
._exposureGlobalNames
= scope
.globalNames
488 # Verify that our [Exposed] value, if any, makes sense.
489 for globalName
in self
._exposureGlobalNames
:
490 if globalName
not in scope
.globalNames
:
492 "Unknown [Exposed] value %s" % globalName
, [self
._location
]
495 # Verify that we are exposed _somwhere_ if we have some place to be
496 # exposed. We don't want to assert that we're definitely exposed
497 # because a lot of our parser tests have small-enough IDL snippets that
498 # they don't include any globals, and we don't really want to go through
499 # and add global interfaces and [Exposed] annotations to all those
501 if len(scope
.globalNames
) != 0 and len(self
._exposureGlobalNames
) == 0:
504 "'%s' is not exposed anywhere even though we have "
505 "globals to be exposed to"
511 globalNameSetToExposureSet(scope
, self
._exposureGlobalNames
, self
.exposureSet
)
513 def isExposedInWindow(self
):
514 return "Window" in self
.exposureSet
516 def isExposedInAnyWorker(self
):
517 return len(self
.getWorkerExposureSet()) > 0
519 def isExposedInWorkerDebugger(self
):
520 return len(self
.getWorkerDebuggerExposureSet()) > 0
522 def isExposedInAnyWorklet(self
):
523 return len(self
.getWorkletExposureSet()) > 0
525 def isExposedInSomeButNotAllWorkers(self
):
527 Returns true if the Exposed extended attribute for this interface
528 exposes it in some worker globals but not others. The return value does
529 not depend on whether the interface is exposed in Window or System
532 if not self
.isExposedInAnyWorker():
534 workerScopes
= self
.parentScope
.globalNameMapping
["Worker"]
535 return len(workerScopes
.difference(self
.exposureSet
)) > 0
537 def isExposedInShadowRealms(self
):
538 return "ShadowRealmGlobalScope" in self
.exposureSet
540 def getWorkerExposureSet(self
):
541 workerScopes
= self
._globalScope
.globalNameMapping
["Worker"]
542 return workerScopes
.intersection(self
.exposureSet
)
544 def getWorkletExposureSet(self
):
545 workletScopes
= self
._globalScope
.globalNameMapping
["Worklet"]
546 return workletScopes
.intersection(self
.exposureSet
)
548 def getWorkerDebuggerExposureSet(self
):
549 workerDebuggerScopes
= self
._globalScope
.globalNameMapping
["WorkerDebugger"]
550 return workerDebuggerScopes
.intersection(self
.exposureSet
)
553 class IDLExternalInterface(IDLObjectWithIdentifier
):
554 def __init__(self
, location
, parentScope
, identifier
):
555 assert isinstance(identifier
, IDLUnresolvedIdentifier
)
556 assert isinstance(parentScope
, IDLScope
)
558 IDLObjectWithIdentifier
.__init
__(self
, location
, parentScope
, identifier
)
559 IDLObjectWithIdentifier
.resolve(self
, parentScope
)
561 def finish(self
, scope
):
567 def isIteratorInterface(self
):
570 def isAsyncIteratorInterface(self
):
573 def isExternal(self
):
576 def isInterface(self
):
579 def addExtendedAttributes(self
, attrs
):
582 "There are no extended attributes that are "
583 "allowed on external interfaces",
584 [attrs
[0].location
, self
.location
],
587 def resolve(self
, parentScope
):
590 def getJSImplementation(self
):
593 def isJSImplemented(self
):
596 def hasProbablyShortLivingWrapper(self
):
599 def _getDependentObjects(self
):
603 class IDLPartialDictionary(IDLObject
):
604 def __init__(self
, location
, name
, members
, nonPartialDictionary
):
605 assert isinstance(name
, IDLUnresolvedIdentifier
)
607 IDLObject
.__init
__(self
, location
)
608 self
.identifier
= name
609 self
.members
= members
610 self
._nonPartialDictionary
= nonPartialDictionary
611 self
._finished
= False
612 nonPartialDictionary
.addPartialDictionary(self
)
614 def addExtendedAttributes(self
, attrs
):
617 def finish(self
, scope
):
620 self
._finished
= True
622 # Need to make sure our non-partial dictionary gets
623 # finished so it can report cases when we only have partial
625 self
._nonPartialDictionary
.finish(scope
)
631 class IDLPartialInterfaceOrNamespace(IDLObject
):
632 def __init__(self
, location
, name
, members
, nonPartialInterfaceOrNamespace
):
633 assert isinstance(name
, IDLUnresolvedIdentifier
)
635 IDLObject
.__init
__(self
, location
)
636 self
.identifier
= name
637 self
.members
= members
638 # propagatedExtendedAttrs are the ones that should get
639 # propagated to our non-partial interface.
640 self
.propagatedExtendedAttrs
= []
641 self
._haveSecureContextExtendedAttribute
= False
642 self
._nonPartialInterfaceOrNamespace
= nonPartialInterfaceOrNamespace
643 self
._finished
= False
644 nonPartialInterfaceOrNamespace
.addPartial(self
)
646 def addExtendedAttributes(self
, attrs
):
648 identifier
= attr
.identifier()
650 if identifier
== "LegacyFactoryFunction":
651 self
.propagatedExtendedAttrs
.append(attr
)
652 elif identifier
== "SecureContext":
653 self
._haveSecureContextExtendedAttribute
= True
654 # This gets propagated to all our members.
655 for member
in self
.members
:
656 if member
.getExtendedAttribute("SecureContext"):
658 "[SecureContext] specified on both a "
659 "partial interface member and on the "
660 "partial interface itself",
661 [member
.location
, attr
.location
],
663 member
.addExtendedAttributes([attr
])
664 elif identifier
== "Exposed":
665 # This just gets propagated to all our members.
666 for member
in self
.members
:
667 if len(member
._exposureGlobalNames
) != 0:
669 "[Exposed] specified on both a "
670 "partial interface member and on the "
671 "partial interface itself",
672 [member
.location
, attr
.location
],
674 member
.addExtendedAttributes([attr
])
677 "Unknown extended attribute %s on partial "
678 "interface" % identifier
,
682 def finish(self
, scope
):
685 self
._finished
= True
687 not self
._haveSecureContextExtendedAttribute
688 and self
._nonPartialInterfaceOrNamespace
.getExtendedAttribute(
692 # This gets propagated to all our members.
693 for member
in self
.members
:
694 if member
.getExtendedAttribute("SecureContext"):
696 "[SecureContext] specified on both a "
697 "partial interface member and on the "
698 "non-partial interface",
701 self
._nonPartialInterfaceOrNamespace
.location
,
704 member
.addExtendedAttributes(
706 IDLExtendedAttribute(
707 self
._nonPartialInterfaceOrNamespace
.location
,
712 # Need to make sure our non-partial interface or namespace gets
713 # finished so it can report cases when we only have partial
714 # interfaces/namespaces.
715 self
._nonPartialInterfaceOrNamespace
.finish(scope
)
721 def convertExposedAttrToGlobalNameSet(exposedAttr
, targetSet
):
722 assert len(targetSet
) == 0
723 if exposedAttr
.hasValue():
724 targetSet
.add(exposedAttr
.value())
726 assert exposedAttr
.hasArgs()
727 targetSet
.update(exposedAttr
.args())
730 def globalNameSetToExposureSet(globalScope
, nameSet
, exposureSet
):
732 exposureSet
.update(globalScope
.globalNameMapping
[name
])
735 # Because WebIDL allows static and regular operations with the same identifier
736 # we use a special class to be able to store them both in the scope for the
739 def __init__(self
, static
=None, regular
=None):
741 self
.regular
= regular
744 class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope
, IDLExposureMixins
):
745 def __init__(self
, location
, parentScope
, name
):
746 assert isinstance(parentScope
, IDLScope
)
747 assert isinstance(name
, IDLUnresolvedIdentifier
)
749 self
._finished
= False
752 self
._extendedAttrDict
= {}
753 self
._isKnownNonPartial
= False
755 IDLObjectWithScope
.__init
__(self
, location
, parentScope
, name
)
756 IDLExposureMixins
.__init
__(self
, location
)
758 def finish(self
, scope
):
759 if not self
._isKnownNonPartial
:
761 "%s does not have a non-partial declaration" % str(self
),
765 IDLExposureMixins
.finish(self
, scope
)
767 # Now go ahead and merge in our partials.
768 for partial
in self
._partials
:
769 partial
.finish(scope
)
770 self
.addExtendedAttributes(partial
.propagatedExtendedAttrs
)
771 self
.members
.extend(partial
.members
)
773 def addNewIdentifier(self
, identifier
, object):
774 if isinstance(object, IDLMethod
):
775 if object.isStatic():
776 object = IDLOperations(static
=object)
778 object = IDLOperations(regular
=object)
780 IDLScope
.addNewIdentifier(self
, identifier
, object)
782 def resolveIdentifierConflict(self
, scope
, identifier
, originalObject
, newObject
):
783 assert isinstance(scope
, IDLScope
)
784 assert isinstance(newObject
, IDLInterfaceMember
)
786 # The identifier of a regular operation or static operation must not be
787 # the same as the identifier of a constant or attribute.
788 if isinstance(newObject
, IDLMethod
) != isinstance(
789 originalObject
, IDLOperations
791 if isinstance(originalObject
, IDLOperations
):
792 if originalObject
.regular
is not None:
793 originalObject
= originalObject
.regular
795 assert originalObject
.static
is not None
796 originalObject
= originalObject
.static
798 raise self
.createIdentifierConflictError(
799 identifier
, originalObject
, newObject
802 if isinstance(newObject
, IDLMethod
):
803 originalOperations
= originalObject
804 if newObject
.isStatic():
805 if originalOperations
.static
is None:
806 originalOperations
.static
= newObject
807 return originalOperations
809 originalObject
= originalOperations
.static
811 if originalOperations
.regular
is None:
812 originalOperations
.regular
= newObject
813 return originalOperations
815 originalObject
= originalOperations
.regular
817 assert isinstance(originalObject
, IDLMethod
)
819 assert isinstance(originalObject
, IDLInterfaceMember
)
821 retval
= IDLScope
.resolveIdentifierConflict(
822 self
, scope
, identifier
, originalObject
, newObject
825 if isinstance(newObject
, IDLMethod
):
826 if newObject
.isStatic():
827 originalOperations
.static
= retval
829 originalOperations
.regular
= retval
831 retval
= originalOperations
833 # Might be a ctor, which isn't in self.members
834 if newObject
in self
.members
:
835 self
.members
.remove(newObject
)
839 if self
.isInterface():
841 if self
.isNamespace():
843 assert self
.isInterfaceMixin()
844 return "interface mixin"
846 def getExtendedAttribute(self
, name
):
847 return self
._extendedAttrDict
.get(name
, None)
849 def setNonPartial(self
, location
, members
):
850 if self
._isKnownNonPartial
:
852 "Two non-partial definitions for the " "same %s" % self
.typeName(),
853 [location
, self
.location
],
855 self
._isKnownNonPartial
= True
856 # Now make it look like we were parsed at this new location, since
857 # that's the place where the interface is "really" defined
858 self
.location
= location
859 # Put the new members at the beginning
860 self
.members
= members
+ self
.members
862 def addPartial(self
, partial
):
863 assert self
.identifier
.name
== partial
.identifier
.name
864 self
._partials
.append(partial
)
866 def getPartials(self
):
867 # Don't let people mutate our guts.
868 return list(self
._partials
)
870 def finishMembers(self
, scope
):
871 # Assuming we've merged in our partials, set the _exposureGlobalNames on
872 # any members that don't have it set yet. Note that any partial
873 # interfaces that had [Exposed] set have already set up
874 # _exposureGlobalNames on all the members coming from them, so this is
875 # just implementing the "members default to interface or interface mixin
876 # that defined them" and "partial interfaces or interface mixins default
877 # to interface or interface mixin they're a partial for" rules from the
879 for m
in self
.members
:
880 # If m, or the partial m came from, had [Exposed]
881 # specified, it already has a nonempty exposure global names set.
882 if len(m
._exposureGlobalNames
) == 0:
883 m
._exposureGlobalNames
.update(self
._exposureGlobalNames
)
884 if m
.isAttr() and m
.stringifier
:
885 m
.expand(self
.members
)
887 # resolve() will modify self.members, so we need to iterate
888 # over a copy of the member list here.
889 for member
in list(self
.members
):
892 for member
in self
.members
:
895 # Now that we've finished our members, which has updated their exposure
896 # sets, make sure they aren't exposed in places where we are not.
897 for member
in self
.members
:
898 if not member
.exposureSet
.issubset(self
.exposureSet
):
900 "Interface or interface mixin member has "
901 "larger exposure set than its container",
902 [member
.location
, self
.location
],
905 def isExternal(self
):
909 class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace
):
910 def __init__(self
, location
, parentScope
, name
, members
, isKnownNonPartial
):
911 self
.actualExposureGlobalNames
= set()
913 assert isKnownNonPartial
or len(members
) == 0
914 IDLInterfaceOrInterfaceMixinOrNamespace
.__init
__(
915 self
, location
, parentScope
, name
918 if isKnownNonPartial
:
919 self
.setNonPartial(location
, members
)
922 return "Interface mixin '%s'" % self
.identifier
.name
924 def isInterfaceMixin(self
):
927 def finish(self
, scope
):
930 self
._finished
= True
932 # Expose to the globals of interfaces that includes this mixin if this
933 # mixin has no explicit [Exposed] so that its members can be exposed
934 # based on the base interface exposure set.
936 # Make sure this is done before IDLExposureMixins.finish call, since
937 # that converts our set of exposure global names to an actual exposure
939 hasImplicitExposure
= len(self
._exposureGlobalNames
) == 0
940 if hasImplicitExposure
:
941 self
._exposureGlobalNames
.update(self
.actualExposureGlobalNames
)
943 IDLInterfaceOrInterfaceMixinOrNamespace
.finish(self
, scope
)
945 self
.finishMembers(scope
)
948 for member
in self
.members
:
952 "Interface mixin member cannot include "
953 "an inherited attribute",
954 [member
.location
, self
.location
],
956 if member
.isStatic():
958 "Interface mixin member cannot include " "a static member",
959 [member
.location
, self
.location
],
962 if member
.isMethod():
963 if member
.isStatic():
965 "Interface mixin member cannot include " "a static operation",
966 [member
.location
, self
.location
],
971 or member
.isDeleter()
972 or member
.isLegacycaller()
975 "Interface mixin member cannot include a " "special operation",
976 [member
.location
, self
.location
],
979 def addExtendedAttributes(self
, attrs
):
981 identifier
= attr
.identifier()
983 if identifier
== "SecureContext":
984 if not attr
.noArguments():
986 "[%s] must take no arguments" % identifier
, [attr
.location
]
988 # This gets propagated to all our members.
989 for member
in self
.members
:
990 if member
.getExtendedAttribute("SecureContext"):
992 "[SecureContext] specified on both "
993 "an interface mixin member and on"
994 "the interface mixin itself",
995 [member
.location
, attr
.location
],
997 member
.addExtendedAttributes([attr
])
998 elif identifier
== "Exposed":
999 convertExposedAttrToGlobalNameSet(attr
, self
._exposureGlobalNames
)
1002 "Unknown extended attribute %s on interface" % identifier
,
1006 attrlist
= attr
.listValue()
1007 self
._extendedAttrDict
[identifier
] = attrlist
if len(attrlist
) else True
1009 def _getDependentObjects(self
):
1010 return set(self
.members
)
1013 class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace
):
1014 def __init__(self
, location
, parentScope
, name
, parent
, members
, isKnownNonPartial
):
1015 assert isKnownNonPartial
or not parent
1016 assert isKnownNonPartial
or len(members
) == 0
1019 self
._callback
= False
1020 self
.maplikeOrSetlikeOrIterable
= None
1021 # legacyFactoryFunctions needs deterministic ordering because bindings code
1022 # outputs the constructs in the order that legacyFactoryFunctions enumerates
1024 self
.legacyFactoryFunctions
= list()
1025 self
.legacyWindowAliases
= []
1026 self
.includedMixins
= set()
1027 # self.interfacesBasedOnSelf is the set of interfaces that inherit from
1028 # self, including self itself.
1029 # Used for distinguishability checking.
1030 self
.interfacesBasedOnSelf
= set([self
])
1031 self
._hasChildInterfaces
= False
1032 self
._isOnGlobalProtoChain
= False
1034 # Tracking of the number of reserved slots we need for our
1035 # members and those of ancestor interfaces.
1036 self
.totalMembersInSlots
= 0
1037 # Tracking of the number of own own members we have in slots
1038 self
._ownMembersInSlots
= 0
1039 # If this is an iterator interface, we need to know what iterable
1040 # interface we're iterating for in order to get its nativeType.
1041 self
.iterableInterface
= None
1042 self
.asyncIterableInterface
= None
1043 # True if we have cross-origin members.
1044 self
.hasCrossOriginMembers
= False
1045 # True if some descendant (including ourselves) has cross-origin members
1046 self
.hasDescendantWithCrossOriginMembers
= False
1048 IDLInterfaceOrInterfaceMixinOrNamespace
.__init
__(
1049 self
, location
, parentScope
, name
1052 if isKnownNonPartial
:
1053 self
.setNonPartial(location
, parent
, members
)
1056 identifier
= IDLUnresolvedIdentifier(
1057 self
.location
, "constructor", allowForbidden
=True
1060 return self
._lookupIdentifier
(identifier
).static
1064 def isIterable(self
):
1066 self
.maplikeOrSetlikeOrIterable
1067 and self
.maplikeOrSetlikeOrIterable
.isIterable()
1070 def isAsyncIterable(self
):
1072 self
.maplikeOrSetlikeOrIterable
1073 and self
.maplikeOrSetlikeOrIterable
.isAsyncIterable()
1076 def isIteratorInterface(self
):
1077 return self
.iterableInterface
is not None
1079 def isAsyncIteratorInterface(self
):
1080 return self
.asyncIterableInterface
is not None
1082 def getClassName(self
):
1083 return self
.identifier
.name
1085 def finish(self
, scope
):
1089 self
._finished
= True
1091 IDLInterfaceOrInterfaceMixinOrNamespace
.finish(self
, scope
)
1093 if len(self
.legacyWindowAliases
) > 0:
1094 if not self
.hasInterfaceObject():
1096 "Interface %s unexpectedly has [LegacyWindowAlias] "
1097 "and [LegacyNoInterfaceObject] together" % self
.identifier
.name
,
1100 if not self
.isExposedInWindow():
1102 "Interface %s has [LegacyWindowAlias] "
1103 "but not exposed in Window" % self
.identifier
.name
,
1107 # Generate maplike/setlike interface members. Since generated members
1108 # need to be treated like regular interface members, do this before
1109 # things like exposure setting.
1110 for member
in self
.members
:
1111 if member
.isMaplikeOrSetlikeOrIterable():
1112 if self
.isJSImplemented():
1114 "%s declaration used on "
1115 "interface that is implemented in JS"
1116 % (member
.maplikeOrSetlikeOrIterableType
),
1119 if member
.valueType
.isObservableArray() or (
1120 member
.hasKeyType() and member
.keyType
.isObservableArray()
1123 "%s declaration uses ObservableArray as value or key type"
1124 % (member
.maplikeOrSetlikeOrIterableType
),
1127 # Check that we only have one interface declaration (currently
1128 # there can only be one maplike/setlike declaration per
1130 if self
.maplikeOrSetlikeOrIterable
:
1132 "%s declaration used on "
1133 "interface that already has %s "
1136 member
.maplikeOrSetlikeOrIterableType
,
1137 self
.maplikeOrSetlikeOrIterable
.maplikeOrSetlikeOrIterableType
,
1139 [self
.maplikeOrSetlikeOrIterable
.location
, member
.location
],
1141 self
.maplikeOrSetlikeOrIterable
= member
1142 # If we've got a maplike or setlike declaration, we'll be building all of
1143 # our required methods in Codegen. Generate members now.
1144 self
.maplikeOrSetlikeOrIterable
.expand(self
.members
)
1146 assert not self
.parent
or isinstance(self
.parent
, IDLIdentifierPlaceholder
)
1147 parent
= self
.parent
.finish(scope
) if self
.parent
else None
1148 if parent
and isinstance(parent
, IDLExternalInterface
):
1150 "%s inherits from %s which does not have "
1151 "a definition" % (self
.identifier
.name
, self
.parent
.identifier
.name
),
1154 if parent
and not isinstance(parent
, IDLInterface
):
1156 "%s inherits from %s which is not an interface "
1157 % (self
.identifier
.name
, self
.parent
.identifier
.name
),
1158 [self
.location
, parent
.location
],
1161 self
.parent
= parent
1163 assert iter(self
.members
)
1165 if self
.isNamespace():
1166 assert not self
.parent
1167 for m
in self
.members
:
1168 if m
.isAttr() or m
.isMethod():
1171 "Don't mark things explicitly static " "in namespaces",
1172 [self
.location
, m
.location
],
1174 # Just mark all our methods/attributes as static. The other
1175 # option is to duplicate the relevant InterfaceMembers
1176 # production bits but modified to produce static stuff to
1177 # start with, but that sounds annoying.
1181 self
.parent
.finish(scope
)
1182 self
.parent
._hasChildInterfaces
= True
1184 self
.totalMembersInSlots
= self
.parent
.totalMembersInSlots
1186 # Interfaces with [Global] must not have anything inherit from them
1187 if self
.parent
.getExtendedAttribute("Global"):
1188 # Note: This is not a self.parent.isOnGlobalProtoChain() check
1189 # because ancestors of a [Global] interface can have other
1192 "[Global] interface has another interface " "inheriting from it",
1193 [self
.location
, self
.parent
.location
],
1196 # Make sure that we're not exposed in places where our parent is not
1197 if not self
.exposureSet
.issubset(self
.parent
.exposureSet
):
1199 "Interface %s is exposed in globals where its "
1200 "parent interface %s is not exposed."
1201 % (self
.identifier
.name
, self
.parent
.identifier
.name
),
1202 [self
.location
, self
.parent
.location
],
1205 # Callbacks must not inherit from non-callbacks.
1206 # XXXbz Can non-callbacks inherit from callbacks? Spec issue pending.
1207 if self
.isCallback():
1208 if not self
.parent
.isCallback():
1210 "Callback interface %s inheriting from "
1211 "non-callback interface %s"
1212 % (self
.identifier
.name
, self
.parent
.identifier
.name
),
1213 [self
.location
, self
.parent
.location
],
1215 elif self
.parent
.isCallback():
1217 "Non-callback interface %s inheriting from "
1218 "callback interface %s"
1219 % (self
.identifier
.name
, self
.parent
.identifier
.name
),
1220 [self
.location
, self
.parent
.location
],
1223 # Interfaces which have interface objects can't inherit
1224 # from [LegacyNoInterfaceObject] interfaces.
1225 if self
.parent
.getExtendedAttribute(
1226 "LegacyNoInterfaceObject"
1227 ) and not self
.getExtendedAttribute("LegacyNoInterfaceObject"):
1229 "Interface %s does not have "
1230 "[LegacyNoInterfaceObject] but inherits from "
1231 "interface %s which does"
1232 % (self
.identifier
.name
, self
.parent
.identifier
.name
),
1233 [self
.location
, self
.parent
.location
],
1236 # Interfaces that are not [SecureContext] can't inherit
1237 # from [SecureContext] interfaces.
1238 if self
.parent
.getExtendedAttribute(
1240 ) and not self
.getExtendedAttribute("SecureContext"):
1242 "Interface %s does not have "
1243 "[SecureContext] but inherits from "
1244 "interface %s which does"
1245 % (self
.identifier
.name
, self
.parent
.identifier
.name
),
1246 [self
.location
, self
.parent
.location
],
1249 for mixin
in self
.includedMixins
:
1252 cycleInGraph
= self
.findInterfaceLoopPoint(self
)
1255 "Interface %s has itself as ancestor" % self
.identifier
.name
,
1256 [self
.location
, cycleInGraph
.location
],
1259 self
.finishMembers(scope
)
1262 if ctor
is not None:
1263 if not self
.hasInterfaceObject():
1265 "Can't have both a constructor and [LegacyNoInterfaceObject]",
1266 [self
.location
, ctor
.location
],
1269 if self
.globalNames
:
1271 "Can't have both a constructor and [Global]",
1272 [self
.location
, ctor
.location
],
1275 assert ctor
._exposureGlobalNames
== self
._exposureGlobalNames
1276 ctor
._exposureGlobalNames
.update(self
._exposureGlobalNames
)
1277 # Remove the constructor operation from our member list so
1278 # it doesn't get in the way later.
1279 self
.members
.remove(ctor
)
1281 for ctor
in self
.legacyFactoryFunctions
:
1282 if self
.globalNames
:
1284 "Can't have both a legacy factory function and [Global]",
1285 [self
.location
, ctor
.location
],
1287 assert len(ctor
._exposureGlobalNames
) == 0
1288 ctor
._exposureGlobalNames
.update(self
._exposureGlobalNames
)
1291 # Make a copy of our member list, so things that implement us
1292 # can get those without all the stuff we implement ourselves
1294 self
.originalMembers
= list(self
.members
)
1296 for mixin
in sorted(self
.includedMixins
, key
=lambda x
: x
.identifier
.name
):
1297 for mixinMember
in mixin
.members
:
1298 for member
in self
.members
:
1299 if mixinMember
.identifier
.name
== member
.identifier
.name
and (
1300 not mixinMember
.isMethod()
1301 or not member
.isMethod()
1302 or mixinMember
.isStatic() == member
.isStatic()
1305 "Multiple definitions of %s on %s coming from 'includes' statements"
1306 % (member
.identifier
.name
, self
),
1307 [mixinMember
.location
, member
.location
],
1309 self
.members
.extend(mixin
.members
)
1311 for ancestor
in self
.getInheritedInterfaces():
1312 ancestor
.interfacesBasedOnSelf
.add(self
)
1314 ancestor
.maplikeOrSetlikeOrIterable
is not None
1315 and self
.maplikeOrSetlikeOrIterable
is not None
1318 "Cannot have maplike/setlike on %s that "
1319 "inherits %s, which is already "
1321 % (self
.identifier
.name
, ancestor
.identifier
.name
),
1323 self
.maplikeOrSetlikeOrIterable
.location
,
1324 ancestor
.maplikeOrSetlikeOrIterable
.location
,
1328 # Deal with interfaces marked [LegacyUnforgeable], now that we have our full
1329 # member list, except unforgeables pulled in from parents. We want to
1330 # do this before we set "originatingInterface" on our unforgeable
1332 if self
.getExtendedAttribute("LegacyUnforgeable"):
1333 # Check that the interface already has all the things the
1334 # spec would otherwise require us to synthesize and is
1335 # missing the ones we plan to synthesize.
1336 if not any(m
.isMethod() and m
.isStringifier() for m
in self
.members
):
1338 "LegacyUnforgeable interface %s does not have a "
1339 "stringifier" % self
.identifier
.name
,
1343 for m
in self
.members
:
1344 if m
.identifier
.name
== "toJSON":
1346 "LegacyUnforgeable interface %s has a "
1347 "toJSON so we won't be able to add "
1348 "one ourselves" % self
.identifier
.name
,
1349 [self
.location
, m
.location
],
1352 if m
.identifier
.name
== "valueOf" and not m
.isStatic():
1354 "LegacyUnforgeable interface %s has a valueOf "
1355 "member so we won't be able to add one "
1356 "ourselves" % self
.identifier
.name
,
1357 [self
.location
, m
.location
],
1360 for member
in self
.members
:
1362 (member
.isAttr() or member
.isMethod())
1363 and member
.isLegacyUnforgeable()
1364 and not hasattr(member
, "originatingInterface")
1366 member
.originatingInterface
= self
1368 for member
in self
.members
:
1370 member
.isMethod() and member
.getExtendedAttribute("CrossOriginCallable")
1374 member
.getExtendedAttribute("CrossOriginReadable")
1375 or member
.getExtendedAttribute("CrossOriginWritable")
1378 self
.hasCrossOriginMembers
= True
1381 if self
.hasCrossOriginMembers
:
1384 parent
.hasDescendantWithCrossOriginMembers
= True
1385 parent
= parent
.parent
1387 # Compute slot indices for our members before we pull in unforgeable
1388 # members from our parent. Also, maplike/setlike declarations get a
1389 # slot to hold their backing object.
1390 for member
in self
.members
:
1394 member
.getExtendedAttribute("StoreInSlot")
1395 or member
.getExtendedAttribute("Cached")
1396 or member
.type.isObservableArray()
1398 ) or member
.isMaplikeOrSetlike():
1399 if self
.isJSImplemented() and not member
.isMaplikeOrSetlike():
1401 "Interface %s is JS-implemented and we "
1402 "don't support [Cached] or [StoreInSlot] or ObservableArray "
1403 "on JS-implemented interfaces" % self
.identifier
.name
,
1404 [self
.location
, member
.location
],
1406 if member
.slotIndices
is None:
1407 member
.slotIndices
= dict()
1408 member
.slotIndices
[self
.identifier
.name
] = self
.totalMembersInSlots
1409 self
.totalMembersInSlots
+= 1
1410 if member
.getExtendedAttribute("StoreInSlot"):
1411 self
._ownMembersInSlots
+= 1
1414 # Make sure we don't shadow any of the [LegacyUnforgeable] attributes on our
1415 # ancestor interfaces. We don't have to worry about mixins here, because
1416 # those have already been imported into the relevant .members lists. And
1417 # we don't have to worry about anything other than our parent, because it
1418 # has already imported its ancestors' unforgeable attributes into its
1420 for unforgeableMember
in (
1422 for member
in self
.parent
.members
1423 if (member
.isAttr() or member
.isMethod())
1424 and member
.isLegacyUnforgeable()
1428 for m
in self
.members
1429 if (m
.isAttr() or m
.isMethod())
1430 and not m
.isStatic()
1431 and m
.identifier
.name
== unforgeableMember
.identifier
.name
1433 if len(shadows
) != 0:
1434 locs
= [unforgeableMember
.location
] + [s
.location
for s
in shadows
]
1436 "Interface %s shadows [LegacyUnforgeable] "
1438 % (self
.identifier
.name
, ancestor
.identifier
.name
),
1441 # And now just stick it in our members, since we won't be
1442 # inheriting this down the proto chain. If we really cared we
1443 # could try to do something where we set up the unforgeable
1444 # attributes/methods of ancestor interfaces, with their
1445 # corresponding getters, on our interface, but that gets pretty
1446 # complicated and seems unnecessary.
1447 self
.members
.append(unforgeableMember
)
1449 # At this point, we have all of our members. If the current interface
1450 # uses maplike/setlike, check for collisions anywhere in the current
1451 # interface or higher in the inheritance chain.
1452 if self
.maplikeOrSetlikeOrIterable
:
1453 testInterface
= self
1455 while testInterface
:
1456 self
.maplikeOrSetlikeOrIterable
.checkCollisions(
1457 testInterface
.members
, isAncestor
1460 testInterface
= testInterface
.parent
1462 # Ensure that there's at most one of each {named,indexed}
1463 # {getter,setter,deleter}, at most one stringifier,
1464 # and at most one legacycaller. Note that this last is not
1465 # quite per spec, but in practice no one overloads
1466 # legacycallers. Also note that in practice we disallow
1467 # indexed deleters, but it simplifies some other code to
1468 # treat deleter analogously to getter/setter by
1469 # prefixing it with "named".
1470 specialMembersSeen
= {}
1471 for member
in self
.members
:
1472 if not member
.isMethod():
1475 if member
.isGetter():
1476 memberType
= "getters"
1477 elif member
.isSetter():
1478 memberType
= "setters"
1479 elif member
.isDeleter():
1480 memberType
= "deleters"
1481 elif member
.isStringifier():
1482 memberType
= "stringifiers"
1483 elif member
.isLegacycaller():
1484 memberType
= "legacycallers"
1488 if memberType
!= "stringifiers" and memberType
!= "legacycallers":
1489 if member
.isNamed():
1490 memberType
= "named " + memberType
1492 assert member
.isIndexed()
1493 memberType
= "indexed " + memberType
1495 if memberType
in specialMembersSeen
:
1497 "Multiple " + memberType
+ " on %s" % (self
),
1500 specialMembersSeen
[memberType
].location
,
1505 specialMembersSeen
[memberType
] = member
1507 if self
.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
1508 # Check that we have a named getter.
1509 if "named getters" not in specialMembersSeen
:
1511 "Interface with [LegacyUnenumerableNamedProperties] does "
1512 "not have a named getter",
1515 ancestor
= self
.parent
1517 if ancestor
.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
1519 "Interface with [LegacyUnenumerableNamedProperties] "
1520 "inherits from another interface with "
1521 "[LegacyUnenumerableNamedProperties]",
1522 [self
.location
, ancestor
.location
],
1524 ancestor
= ancestor
.parent
1526 if self
._isOnGlobalProtoChain
:
1527 # Make sure we have no named setters or deleters
1528 for memberType
in ["setter", "deleter"]:
1529 memberId
= "named " + memberType
+ "s"
1530 if memberId
in specialMembersSeen
:
1532 "Interface with [Global] has a named %s" % memberType
,
1533 [self
.location
, specialMembersSeen
[memberId
].location
],
1535 # Make sure we're not [LegacyOverrideBuiltIns]
1536 if self
.getExtendedAttribute("LegacyOverrideBuiltIns"):
1538 "Interface with [Global] also has " "[LegacyOverrideBuiltIns]",
1541 # Mark all of our ancestors as being on the global's proto chain too
1542 parent
= self
.parent
1544 # Must not inherit from an interface with [LegacyOverrideBuiltIns]
1545 if parent
.getExtendedAttribute("LegacyOverrideBuiltIns"):
1547 "Interface with [Global] inherits from "
1548 "interface with [LegacyOverrideBuiltIns]",
1549 [self
.location
, parent
.location
],
1551 parent
._isOnGlobalProtoChain
= True
1552 parent
= parent
.parent
1555 def checkDuplicateNames(member
, name
, attributeName
):
1556 for m
in self
.members
:
1557 if m
.identifier
.name
== name
:
1559 "[%s=%s] has same name as interface member"
1560 % (attributeName
, name
),
1561 [member
.location
, m
.location
],
1563 if m
.isMethod() and m
!= member
and name
in m
.aliases
:
1565 "conflicting [%s=%s] definitions" % (attributeName
, name
),
1566 [member
.location
, m
.location
],
1568 if m
.isAttr() and m
!= member
and name
in m
.bindingAliases
:
1570 "conflicting [%s=%s] definitions" % (attributeName
, name
),
1571 [member
.location
, m
.location
],
1574 # We also don't support inheriting from unforgeable interfaces.
1575 if self
.getExtendedAttribute("LegacyUnforgeable") and self
.hasChildInterfaces():
1576 locations
= [self
.location
] + list(
1577 i
.location
for i
in self
.interfacesBasedOnSelf
if i
.parent
== self
1580 "%s is an unforgeable ancestor interface" % self
.identifier
.name
,
1585 if ctor
is not None:
1587 for namedCtor
in self
.legacyFactoryFunctions
:
1588 namedCtor
.validate()
1590 indexedGetter
= None
1591 hasLengthAttribute
= False
1592 for member
in self
.members
:
1595 if self
.isCallback() and member
.getExtendedAttribute("Replaceable"):
1597 "[Replaceable] used on an attribute on "
1598 "interface %s which is a callback interface" % self
.identifier
.name
,
1599 [self
.location
, member
.location
],
1602 # Check that PutForwards refers to another attribute and that no
1603 # cycles exist in forwarded assignments. Also check for a
1604 # integer-typed "length" attribute.
1606 if member
.identifier
.name
== "length" and member
.type.isInteger():
1607 hasLengthAttribute
= True
1611 putForwards
= attr
.getExtendedAttribute("PutForwards")
1612 if putForwards
and self
.isCallback():
1614 "[PutForwards] used on an attribute "
1615 "on interface %s which is a callback "
1616 "interface" % self
.identifier
.name
,
1617 [self
.location
, member
.location
],
1620 while putForwards
is not None:
1621 forwardIface
= attr
.type.unroll().inner
1624 for forwardedMember
in forwardIface
.members
:
1626 not forwardedMember
.isAttr()
1627 or forwardedMember
.identifier
.name
!= putForwards
[0]
1630 if forwardedMember
== member
:
1632 "Cycle detected in forwarded "
1633 "assignments for attribute %s on "
1634 "%s" % (member
.identifier
.name
, self
),
1637 fowardAttr
= forwardedMember
1640 if fowardAttr
is None:
1642 "Attribute %s on %s forwards to "
1643 "missing attribute %s"
1644 % (attr
.identifier
.name
, iface
, putForwards
),
1648 iface
= forwardIface
1650 putForwards
= attr
.getExtendedAttribute("PutForwards")
1652 # Check that the name of an [Alias] doesn't conflict with an
1653 # interface member and whether we support indexed properties.
1654 if member
.isMethod():
1655 if member
.isGetter() and member
.isIndexed():
1656 indexedGetter
= member
1658 for alias
in member
.aliases
:
1659 if self
.isOnGlobalProtoChain():
1661 "[Alias] must not be used on a "
1662 "[Global] interface operation",
1666 member
.getExtendedAttribute("Exposed")
1667 or member
.getExtendedAttribute("ChromeOnly")
1668 or member
.getExtendedAttribute("Pref")
1669 or member
.getExtendedAttribute("Func")
1670 or member
.getExtendedAttribute("Trial")
1671 or member
.getExtendedAttribute("SecureContext")
1674 "[Alias] must not be used on a "
1675 "conditionally exposed operation",
1678 if member
.isStatic():
1680 "[Alias] must not be used on a " "static operation",
1683 if member
.isIdentifierLess():
1685 "[Alias] must not be used on an "
1686 "identifierless operation",
1689 if member
.isLegacyUnforgeable():
1691 "[Alias] must not be used on an "
1692 "[LegacyUnforgeable] operation",
1696 checkDuplicateNames(member
, alias
, "Alias")
1698 # Check that the name of a [BindingAlias] doesn't conflict with an
1701 for bindingAlias
in member
.bindingAliases
:
1702 checkDuplicateNames(member
, bindingAlias
, "BindingAlias")
1704 # Conditional exposure makes no sense for interfaces with no
1706 # And SecureContext makes sense for interfaces with no interface object,
1707 # since it is also propagated to interface members.
1709 self
.isExposedConditionally(exclusions
=["SecureContext"])
1710 and not self
.hasInterfaceObject()
1713 "Interface with no interface object is " "exposed conditionally",
1717 # Value iterators are only allowed on interfaces with indexed getters,
1718 # and pair iterators are only allowed on interfaces without indexed
1720 if self
.isIterable():
1721 iterableDecl
= self
.maplikeOrSetlikeOrIterable
1722 if iterableDecl
.isValueIterator():
1723 if not indexedGetter
:
1725 "Interface with value iterator does not "
1726 "support indexed properties",
1727 [self
.location
, iterableDecl
.location
],
1730 if iterableDecl
.valueType
!= indexedGetter
.signatures()[0][0]:
1732 "Iterable type does not match indexed " "getter type",
1733 [iterableDecl
.location
, indexedGetter
.location
],
1736 if not hasLengthAttribute
:
1738 "Interface with value iterator does not "
1739 'have an integer-typed "length" attribute',
1740 [self
.location
, iterableDecl
.location
],
1743 assert iterableDecl
.isPairIterator()
1746 "Interface with pair iterator supports " "indexed properties",
1747 [self
.location
, iterableDecl
.location
, indexedGetter
.location
],
1750 if indexedGetter
and not hasLengthAttribute
:
1752 "Interface with an indexed getter does not have "
1753 'an integer-typed "length" attribute',
1754 [self
.location
, indexedGetter
.location
],
1757 def setCallback(self
, value
):
1758 self
._callback
= value
1760 def isCallback(self
):
1761 return self
._callback
1763 def isSingleOperationInterface(self
):
1764 assert self
.isCallback() or self
.isJSImplemented()
1766 # JS-implemented things should never need the
1767 # this-handling weirdness of single-operation interfaces.
1768 not self
.isJSImplemented()
1770 # Not inheriting from another interface
1773 # No attributes of any kinds
1774 not any(m
.isAttr() for m
in self
.members
)
1776 # There is at least one regular operation, and all regular
1777 # operations have the same identifier
1781 for m
in self
.members
1782 if m
.isMethod() and not m
.isStatic()
1788 def inheritanceDepth(self
):
1790 parent
= self
.parent
1793 parent
= parent
.parent
1796 def hasConstants(self
):
1797 return any(m
.isConst() for m
in self
.members
)
1799 def hasInterfaceObject(self
):
1800 if self
.isCallback():
1801 return self
.hasConstants()
1802 return not hasattr(self
, "_noInterfaceObject")
1804 def hasInterfacePrototypeObject(self
):
1806 not self
.isCallback()
1807 and not self
.isNamespace()
1808 and self
.getUserData("hasConcreteDescendant", False)
1811 def addIncludedMixin(self
, includedMixin
):
1812 assert isinstance(includedMixin
, IDLInterfaceMixin
)
1813 self
.includedMixins
.add(includedMixin
)
1815 def getInheritedInterfaces(self
):
1817 Returns a list of the interfaces this interface inherits from
1818 (not including this interface itself). The list is in order
1819 from most derived to least derived.
1821 assert self
._finished
1824 parentInterfaces
= self
.parent
.getInheritedInterfaces()
1825 parentInterfaces
.insert(0, self
.parent
)
1826 return parentInterfaces
1828 def findInterfaceLoopPoint(self
, otherInterface
):
1830 Finds an interface amongst our ancestors that inherits from otherInterface.
1831 If there is no such interface, returns None.
1834 if self
.parent
== otherInterface
:
1836 loopPoint
= self
.parent
.findInterfaceLoopPoint(otherInterface
)
1841 def setNonPartial(self
, location
, parent
, members
):
1842 assert not parent
or isinstance(parent
, IDLIdentifierPlaceholder
)
1843 IDLInterfaceOrInterfaceMixinOrNamespace
.setNonPartial(self
, location
, members
)
1844 assert not self
.parent
1845 self
.parent
= parent
1847 def getJSImplementation(self
):
1848 classId
= self
.getExtendedAttribute("JSImplementation")
1851 assert isinstance(classId
, list)
1852 assert len(classId
) == 1
1855 def isJSImplemented(self
):
1856 return bool(self
.getJSImplementation())
1858 def hasProbablyShortLivingWrapper(self
):
1861 if current
.getExtendedAttribute("ProbablyShortLivingWrapper"):
1863 current
= current
.parent
1866 def hasChildInterfaces(self
):
1867 return self
._hasChildInterfaces
1869 def isOnGlobalProtoChain(self
):
1870 return self
._isOnGlobalProtoChain
1872 def _getDependentObjects(self
):
1873 deps
= set(self
.members
)
1874 deps
.update(self
.includedMixins
)
1876 deps
.add(self
.parent
)
1879 def hasMembersInSlots(self
):
1880 return self
._ownMembersInSlots
!= 0
1882 conditionExtendedAttributes
= [
1890 def isExposedConditionally(self
, exclusions
=[]):
1892 ((a
not in exclusions
) and self
.getExtendedAttribute(a
))
1893 for a
in self
.conditionExtendedAttributes
1897 class IDLInterface(IDLInterfaceOrNamespace
):
1906 classNameOverride
=None,
1908 IDLInterfaceOrNamespace
.__init
__(
1909 self
, location
, parentScope
, name
, parent
, members
, isKnownNonPartial
1911 self
.classNameOverride
= classNameOverride
1914 return "Interface '%s'" % self
.identifier
.name
1916 def isInterface(self
):
1919 def getClassName(self
):
1920 if self
.classNameOverride
:
1921 return self
.classNameOverride
1922 return IDLInterfaceOrNamespace
.getClassName(self
)
1924 def addExtendedAttributes(self
, attrs
):
1926 identifier
= attr
.identifier()
1928 # Special cased attrs
1929 if identifier
== "TreatNonCallableAsNull":
1931 "TreatNonCallableAsNull cannot be specified on interfaces",
1932 [attr
.location
, self
.location
],
1934 if identifier
== "LegacyTreatNonObjectAsNull":
1936 "LegacyTreatNonObjectAsNull cannot be specified on interfaces",
1937 [attr
.location
, self
.location
],
1939 elif identifier
== "LegacyNoInterfaceObject":
1940 if not attr
.noArguments():
1942 "[LegacyNoInterfaceObject] must take no arguments",
1946 self
._noInterfaceObject
= True
1947 elif identifier
== "LegacyFactoryFunction":
1948 if not attr
.hasValue():
1951 "LegacyFactoryFunction must either take an "
1952 "identifier or take a named argument list"
1957 args
= attr
.args() if attr
.hasArgs() else []
1959 method
= IDLConstructor(attr
.location
, args
, attr
.value())
1960 method
.reallyInit(self
)
1962 # Legacy factory functions are always assumed to be able to
1963 # throw (since there's no way to indicate otherwise).
1964 method
.addExtendedAttributes(
1965 [IDLExtendedAttribute(self
.location
, ("Throws",))]
1968 # We need to detect conflicts for LegacyFactoryFunctions across
1969 # interfaces. We first call resolve on the parentScope,
1970 # which will merge all LegacyFactoryFunctions with the same
1971 # identifier accross interfaces as overloads.
1972 method
.resolve(self
.parentScope
)
1974 # Then we look up the identifier on the parentScope. If the
1975 # result is the same as the method we're adding then it
1976 # hasn't been added as an overload and it's the first time
1977 # we've encountered a LegacyFactoryFunction with that identifier.
1978 # If the result is not the same as the method we're adding
1979 # then it has been added as an overload and we need to check
1980 # whether the result is actually one of our existing
1981 # LegacyFactoryFunctions.
1982 newMethod
= self
.parentScope
.lookupIdentifier(method
.identifier
)
1983 if newMethod
== method
:
1984 self
.legacyFactoryFunctions
.append(method
)
1985 elif newMethod
not in self
.legacyFactoryFunctions
:
1987 "LegacyFactoryFunction conflicts with a "
1988 "LegacyFactoryFunction of a different interface",
1989 [method
.location
, newMethod
.location
],
1991 elif identifier
== "ExceptionClass":
1992 if not attr
.noArguments():
1994 "[ExceptionClass] must take no arguments", [attr
.location
]
1998 "[ExceptionClass] must not be specified on "
1999 "an interface with inherited interfaces",
2000 [attr
.location
, self
.location
],
2002 elif identifier
== "Global":
2004 self
.globalNames
= [attr
.value()]
2005 elif attr
.hasArgs():
2006 self
.globalNames
= attr
.args()
2008 self
.globalNames
= [self
.identifier
.name
]
2009 self
.parentScope
.addIfaceGlobalNames(
2010 self
.identifier
.name
, self
.globalNames
2012 self
._isOnGlobalProtoChain
= True
2013 elif identifier
== "LegacyWindowAlias":
2015 self
.legacyWindowAliases
= [attr
.value()]
2016 elif attr
.hasArgs():
2017 self
.legacyWindowAliases
= attr
.args()
2020 "[%s] must either take an identifier "
2021 "or take an identifier list" % identifier
,
2024 for alias
in self
.legacyWindowAliases
:
2025 unresolved
= IDLUnresolvedIdentifier(attr
.location
, alias
)
2026 IDLObjectWithIdentifier(attr
.location
, self
.parentScope
, unresolved
)
2027 elif identifier
== "SecureContext":
2028 if not attr
.noArguments():
2030 "[%s] must take no arguments" % identifier
, [attr
.location
]
2032 # This gets propagated to all our members.
2033 for member
in self
.members
:
2034 if member
.getExtendedAttribute("SecureContext"):
2036 "[SecureContext] specified on both "
2037 "an interface member and on the "
2039 [member
.location
, attr
.location
],
2041 member
.addExtendedAttributes([attr
])
2043 identifier
== "NeedResolve"
2044 or identifier
== "LegacyOverrideBuiltIns"
2045 or identifier
== "ChromeOnly"
2046 or identifier
== "LegacyUnforgeable"
2047 or identifier
== "LegacyEventInit"
2048 or identifier
== "ProbablyShortLivingWrapper"
2049 or identifier
== "LegacyUnenumerableNamedProperties"
2050 or identifier
== "RunConstructorInCallerCompartment"
2051 or identifier
== "WantsEventListenerHooks"
2052 or identifier
== "Serializable"
2054 # Known extended attributes that do not take values
2055 if not attr
.noArguments():
2057 "[%s] must take no arguments" % identifier
, [attr
.location
]
2059 elif identifier
== "Exposed":
2060 convertExposedAttrToGlobalNameSet(attr
, self
._exposureGlobalNames
)
2062 identifier
== "Pref"
2063 or identifier
== "JSImplementation"
2064 or identifier
== "HeaderFile"
2065 or identifier
== "Func"
2066 or identifier
== "Trial"
2067 or identifier
== "Deprecated"
2069 # Known extended attributes that take a string value
2070 if not attr
.hasValue():
2072 "[%s] must have a value" % identifier
, [attr
.location
]
2074 elif identifier
== "InstrumentedProps":
2075 # Known extended attributes that take a list
2076 if not attr
.hasArgs():
2078 "[%s] must have arguments" % identifier
, [attr
.location
]
2082 "Unknown extended attribute %s on interface" % identifier
,
2086 attrlist
= attr
.listValue()
2087 self
._extendedAttrDict
[identifier
] = attrlist
if len(attrlist
) else True
2090 IDLInterfaceOrNamespace
.validate(self
)
2091 if self
.parent
and self
.isSerializable() and not self
.parent
.isSerializable():
2093 "Serializable interface inherits from non-serializable "
2094 "interface. Per spec, that means the object should not be "
2095 "serializable, so chances are someone made a mistake here "
2097 [self
.location
, self
.parent
.location
],
2100 def isSerializable(self
):
2101 return self
.getExtendedAttribute("Serializable")
2103 def setNonPartial(self
, location
, parent
, members
):
2104 # Before we do anything else, finish initializing any constructors that
2105 # might be in "members", so we don't have partially-initialized objects
2106 # hanging around. We couldn't do it before now because we needed to have
2107 # to have the IDLInterface on hand to properly set the return type.
2108 for member
in members
:
2109 if isinstance(member
, IDLConstructor
):
2110 member
.reallyInit(self
)
2112 IDLInterfaceOrNamespace
.setNonPartial(self
, location
, parent
, members
)
2115 class IDLNamespace(IDLInterfaceOrNamespace
):
2116 def __init__(self
, location
, parentScope
, name
, members
, isKnownNonPartial
):
2117 IDLInterfaceOrNamespace
.__init
__(
2118 self
, location
, parentScope
, name
, None, members
, isKnownNonPartial
2122 return "Namespace '%s'" % self
.identifier
.name
2124 def isNamespace(self
):
2127 def addExtendedAttributes(self
, attrs
):
2128 # The set of things namespaces support is small enough it's simpler
2129 # to factor out into a separate method than it is to sprinkle
2130 # isNamespace() checks all through
2131 # IDLInterfaceOrNamespace.addExtendedAttributes.
2133 identifier
= attr
.identifier()
2135 if identifier
== "Exposed":
2136 convertExposedAttrToGlobalNameSet(attr
, self
._exposureGlobalNames
)
2137 elif identifier
== "ClassString":
2138 # Takes a string value to override the default "Object" if
2140 if not attr
.hasValue():
2142 "[%s] must have a value" % identifier
, [attr
.location
]
2144 elif identifier
== "ProtoObjectHack" or identifier
== "ChromeOnly":
2145 if not attr
.noArguments():
2147 "[%s] must not have arguments" % identifier
, [attr
.location
]
2150 identifier
== "Pref"
2151 or identifier
== "HeaderFile"
2152 or identifier
== "Func"
2153 or identifier
== "Trial"
2155 # Known extended attributes that take a string value
2156 if not attr
.hasValue():
2158 "[%s] must have a value" % identifier
, [attr
.location
]
2162 "Unknown extended attribute %s on namespace" % identifier
,
2166 attrlist
= attr
.listValue()
2167 self
._extendedAttrDict
[identifier
] = attrlist
if len(attrlist
) else True
2169 def isSerializable(self
):
2173 class IDLDictionary(IDLObjectWithScope
):
2174 def __init__(self
, location
, parentScope
, name
, parent
, members
):
2175 assert isinstance(parentScope
, IDLScope
)
2176 assert isinstance(name
, IDLUnresolvedIdentifier
)
2177 assert not parent
or isinstance(parent
, IDLIdentifierPlaceholder
)
2179 self
.parent
= parent
2180 self
._finished
= False
2181 self
.members
= list(members
)
2182 self
._partialDictionaries
= []
2183 self
._extendedAttrDict
= {}
2184 self
.needsConversionToJS
= False
2185 self
.needsConversionFromJS
= False
2187 IDLObjectWithScope
.__init
__(self
, location
, parentScope
, name
)
2190 return "Dictionary '%s'" % self
.identifier
.name
2192 def isDictionary(self
):
2195 def canBeEmpty(self
):
2197 Returns true if this dictionary can be empty (that is, it has no
2198 required members and neither do any of its ancestors).
2200 return all(member
.optional
for member
in self
.members
) and (
2201 not self
.parent
or self
.parent
.canBeEmpty()
2204 def finish(self
, scope
):
2208 self
._finished
= True
2211 assert isinstance(self
.parent
, IDLIdentifierPlaceholder
)
2212 oldParent
= self
.parent
2213 self
.parent
= self
.parent
.finish(scope
)
2214 if not isinstance(self
.parent
, IDLDictionary
):
2216 "Dictionary %s has parent that is not a dictionary"
2217 % self
.identifier
.name
,
2218 [oldParent
.location
, self
.parent
.location
],
2221 # Make sure the parent resolves all its members before we start
2223 self
.parent
.finish(scope
)
2225 # Now go ahead and merge in our partial dictionaries.
2226 for partial
in self
._partialDictionaries
:
2227 partial
.finish(scope
)
2228 self
.members
.extend(partial
.members
)
2230 for member
in self
.members
:
2231 member
.resolve(self
)
2232 if not member
.isComplete():
2233 member
.complete(scope
)
2234 assert member
.type.isComplete()
2236 # Members of a dictionary are sorted in lexicographic order,
2237 # unless the dictionary opts out.
2238 if not self
.getExtendedAttribute("Unsorted"):
2239 self
.members
.sort(key
=lambda x
: x
.identifier
.name
)
2241 inheritedMembers
= []
2242 ancestor
= self
.parent
2244 if ancestor
== self
:
2246 "Dictionary %s has itself as an ancestor" % self
.identifier
.name
,
2247 [self
.identifier
.location
],
2249 inheritedMembers
.extend(ancestor
.members
)
2250 ancestor
= ancestor
.parent
2252 # Catch name duplication
2253 for inheritedMember
in inheritedMembers
:
2254 for member
in self
.members
:
2255 if member
.identifier
.name
== inheritedMember
.identifier
.name
:
2257 "Dictionary %s has two members with name %s"
2258 % (self
.identifier
.name
, member
.identifier
.name
),
2259 [member
.location
, inheritedMember
.location
],
2263 def typeContainsDictionary(memberType
, dictionary
):
2265 Returns a tuple whose:
2267 - First element is a Boolean value indicating whether
2268 memberType contains dictionary.
2270 - Second element is:
2271 A list of locations that leads from the type that was passed in
2272 the memberType argument, to the dictionary being validated,
2273 if the boolean value in the first element is True.
2275 None, if the boolean value in the first element is False.
2279 memberType
.nullable()
2280 or memberType
.isSequence()
2281 or memberType
.isRecord()
2283 return typeContainsDictionary(memberType
.inner
, dictionary
)
2285 if memberType
.isDictionary():
2286 if memberType
.inner
== dictionary
:
2287 return (True, [memberType
.location
])
2289 (contains
, locations
) = dictionaryContainsDictionary(
2290 memberType
.inner
, dictionary
2293 return (True, [memberType
.location
] + locations
)
2295 if memberType
.isUnion():
2296 for member
in memberType
.flatMemberTypes
:
2297 (contains
, locations
) = typeContainsDictionary(member
, dictionary
)
2299 return (True, locations
)
2301 return (False, None)
2303 def dictionaryContainsDictionary(dictMember
, dictionary
):
2304 for member
in dictMember
.members
:
2305 (contains
, locations
) = typeContainsDictionary(member
.type, dictionary
)
2307 return (True, [member
.location
] + locations
)
2309 if dictMember
.parent
:
2310 if dictMember
.parent
== dictionary
:
2311 return (True, [dictMember
.location
])
2313 (contains
, locations
) = dictionaryContainsDictionary(
2314 dictMember
.parent
, dictionary
2317 return (True, [dictMember
.location
] + locations
)
2319 return (False, None)
2321 for member
in self
.members
:
2322 if member
.type.isDictionary() and member
.type.nullable():
2324 "Dictionary %s has member with nullable "
2325 "dictionary type" % self
.identifier
.name
,
2328 (contains
, locations
) = typeContainsDictionary(member
.type, self
)
2331 "Dictionary %s has member with itself as type."
2332 % self
.identifier
.name
,
2333 [member
.location
] + locations
,
2336 if member
.type.isUndefined():
2338 "Dictionary %s has member with undefined as its type."
2339 % self
.identifier
.name
,
2342 elif member
.type.isUnion():
2343 for unionMember
in member
.type.unroll().flatMemberTypes
:
2344 if unionMember
.isUndefined():
2346 "Dictionary %s has member with a union containing "
2347 "undefined as a type." % self
.identifier
.name
,
2348 [unionMember
.location
],
2351 def getExtendedAttribute(self
, name
):
2352 return self
._extendedAttrDict
.get(name
, None)
2354 def addExtendedAttributes(self
, attrs
):
2356 identifier
= attr
.identifier()
2358 if identifier
== "GenerateInitFromJSON" or identifier
== "GenerateInit":
2359 if not attr
.noArguments():
2361 "[%s] must not have arguments" % identifier
, [attr
.location
]
2363 self
.needsConversionFromJS
= True
2365 identifier
== "GenerateConversionToJS" or identifier
== "GenerateToJSON"
2367 if not attr
.noArguments():
2369 "[%s] must not have arguments" % identifier
, [attr
.location
]
2371 # ToJSON methods require to-JS conversion, because we
2372 # implement ToJSON by converting to a JS object and
2373 # then using JSON.stringify.
2374 self
.needsConversionToJS
= True
2375 elif identifier
== "Unsorted":
2376 if not attr
.noArguments():
2378 "[Unsorted] must take no arguments", [attr
.location
]
2382 "[%s] extended attribute not allowed on "
2383 "dictionaries" % identifier
,
2387 self
._extendedAttrDict
[identifier
] = True
2389 def _getDependentObjects(self
):
2390 deps
= set(self
.members
)
2392 deps
.add(self
.parent
)
2395 def addPartialDictionary(self
, partial
):
2396 assert self
.identifier
.name
== partial
.identifier
.name
2397 self
._partialDictionaries
.append(partial
)
2400 class IDLEnum(IDLObjectWithIdentifier
):
2401 def __init__(self
, location
, parentScope
, name
, values
):
2402 assert isinstance(parentScope
, IDLScope
)
2403 assert isinstance(name
, IDLUnresolvedIdentifier
)
2405 if len(values
) != len(set(values
)):
2407 "Enum %s has multiple identical strings" % name
.name
, [location
]
2410 IDLObjectWithIdentifier
.__init
__(self
, location
, parentScope
, name
)
2411 self
._values
= values
2416 def finish(self
, scope
):
2425 def addExtendedAttributes(self
, attrs
):
2428 "There are no extended attributes that are " "allowed on enums",
2429 [attrs
[0].location
, self
.location
],
2432 def _getDependentObjects(self
):
2436 class IDLType(IDLObject
):
2447 # Additional primitive types
2449 "unrestricted_float",
2451 "unrestricted_double",
2452 # "double" last primitive type to match IDLBuiltinType
2475 def __init__(self
, location
, name
):
2476 IDLObject
.__init
__(self
, location
)
2478 self
.builtin
= False
2479 self
.legacyNullToEmptyString
= False
2481 self
._enforceRange
= False
2482 self
._allowShared
= False
2483 self
._extendedAttrDict
= {}
2490 + hash(self
._enforceRange
)
2491 + hash(self
.legacyNullToEmptyString
)
2492 + hash(self
._allowShared
)
2495 def __eq__(self
, other
):
2498 and self
.builtin
== other
.builtin
2499 and self
.name
== other
.name
2500 and self
._clamp
== other
.hasClamp()
2501 and self
._enforceRange
== other
.hasEnforceRange()
2502 and self
.legacyNullToEmptyString
== other
.legacyNullToEmptyString
2503 and self
._allowShared
== other
.hasAllowShared()
2506 def __ne__(self
, other
):
2507 return not self
== other
2510 return str(self
.name
)
2512 def prettyName(self
):
2514 A name that looks like what this type is named in the IDL spec. By default
2515 this is just our .name, but types that have more interesting spec
2516 representations should override this.
2518 return str(self
.name
)
2526 def isPrimitive(self
):
2529 def isBoolean(self
):
2532 def isNumeric(self
):
2538 def isByteString(self
):
2541 def isDOMString(self
):
2544 def isUSVString(self
):
2547 def isUTF8String(self
):
2550 def isJSString(self
):
2553 def isUndefined(self
):
2556 def isSequence(self
):
2562 def isArrayBuffer(self
):
2565 def isArrayBufferView(self
):
2568 def isTypedArray(self
):
2571 def isBufferSource(self
):
2572 return self
.isArrayBuffer() or self
.isArrayBufferView() or self
.isTypedArray()
2574 def isCallbackInterface(self
):
2577 def isNonCallbackInterface(self
):
2580 def isGeckoInterface(self
):
2581 """Returns a boolean indicating whether this type is an 'interface'
2582 type that is implemented in Gecko. At the moment, this returns
2583 true for all interface types that are not types from the TypedArray
2585 return self
.isInterface() and not self
.isSpiderMonkeyInterface()
2587 def isSpiderMonkeyInterface(self
):
2588 """Returns a boolean indicating whether this type is an 'interface'
2589 type that is implemented in SpiderMonkey."""
2590 return self
.isInterface() and self
.isBufferSource()
2593 return self
.tag() == IDLType
.Tags
.any
2596 return self
.tag() == IDLType
.Tags
.object
2598 def isPromise(self
):
2601 def isComplete(self
):
2604 def includesRestrictedFloat(self
):
2610 def isUnrestricted(self
):
2611 # Should only call this on float types
2612 assert self
.isFloat()
2614 def isJSONType(self
):
2617 def isObservableArray(self
):
2620 def isDictionaryLike(self
):
2621 return self
.isDictionary() or self
.isRecord() or self
.isCallbackInterface()
2626 def hasEnforceRange(self
):
2627 return self
._enforceRange
2629 def hasAllowShared(self
):
2630 return self
._allowShared
2633 assert False # Override me!
2635 def treatNonCallableAsNull(self
):
2636 assert self
.tag() == IDLType
.Tags
.callback
2637 return self
.nullable() and self
.inner
.callback
._treatNonCallableAsNull
2639 def treatNonObjectAsNull(self
):
2640 assert self
.tag() == IDLType
.Tags
.callback
2641 return self
.nullable() and self
.inner
.callback
._treatNonObjectAsNull
2643 def withExtendedAttributes(self
, attrs
):
2646 "Extended attributes on types only supported for builtins",
2647 [attrs
[0].location
, self
.location
],
2651 def getExtendedAttribute(self
, name
):
2652 return self
._extendedAttrDict
.get(name
, None)
2654 def resolveType(self
, parentScope
):
2660 def isDistinguishableFrom(self
, other
):
2662 "Can't tell whether a generic type is or is not "
2663 "distinguishable from other things"
2666 def isExposedInAllOf(self
, exposureSet
):
2670 class IDLUnresolvedType(IDLType
):
2672 Unresolved types are interface types
2675 def __init__(self
, location
, name
, attrs
=[]):
2676 IDLType
.__init
__(self
, location
, name
)
2677 self
.extraTypeAttributes
= attrs
2679 def isComplete(self
):
2682 def complete(self
, scope
):
2685 obj
= scope
._lookupIdentifier
(self
.name
)
2687 raise WebIDLError("Unresolved type '%s'." % self
.name
, [self
.location
])
2690 assert not obj
.isType()
2692 assert self
.name
.name
== obj
.identifier
.name
2693 typedefType
= IDLTypedefType(self
.location
, obj
.innerType
, obj
.identifier
)
2694 assert not typedefType
.isComplete()
2695 return typedefType
.complete(scope
).withExtendedAttributes(
2696 self
.extraTypeAttributes
2698 elif obj
.isCallback() and not obj
.isInterface():
2699 assert self
.name
.name
== obj
.identifier
.name
2700 return IDLCallbackType(self
.location
, obj
)
2702 return IDLWrapperType(self
.location
, obj
)
2704 def withExtendedAttributes(self
, attrs
):
2705 return IDLUnresolvedType(self
.location
, self
.name
, attrs
)
2707 def isDistinguishableFrom(self
, other
):
2709 "Can't tell whether an unresolved type is or is not "
2710 "distinguishable from other things"
2714 class IDLParametrizedType(IDLType
):
2715 def __init__(self
, location
, name
, innerType
):
2716 IDLType
.__init
__(self
, location
, name
)
2717 self
.builtin
= False
2718 self
.inner
= innerType
2720 def includesRestrictedFloat(self
):
2721 return self
.inner
.includesRestrictedFloat()
2723 def resolveType(self
, parentScope
):
2724 assert isinstance(parentScope
, IDLScope
)
2725 self
.inner
.resolveType(parentScope
)
2727 def isComplete(self
):
2728 return self
.inner
.isComplete()
2731 return self
.inner
.unroll()
2733 def _getDependentObjects(self
):
2734 return self
.inner
._getDependentObjects
()
2737 class IDLNullableType(IDLParametrizedType
):
2738 def __init__(self
, location
, innerType
):
2739 assert not innerType
== BuiltinTypes
[IDLBuiltinType
.Types
.any
]
2741 IDLParametrizedType
.__init
__(self
, location
, None, innerType
)
2744 return hash(self
.inner
)
2746 def __eq__(self
, other
):
2747 return isinstance(other
, IDLNullableType
) and self
.inner
== other
.inner
2750 return self
.inner
.__str
__() + "OrNull"
2752 def prettyName(self
):
2753 return self
.inner
.prettyName() + "?"
2758 def isCallback(self
):
2759 return self
.inner
.isCallback()
2761 def isPrimitive(self
):
2762 return self
.inner
.isPrimitive()
2764 def isBoolean(self
):
2765 return self
.inner
.isBoolean()
2767 def isNumeric(self
):
2768 return self
.inner
.isNumeric()
2771 return self
.inner
.isString()
2773 def isByteString(self
):
2774 return self
.inner
.isByteString()
2776 def isDOMString(self
):
2777 return self
.inner
.isDOMString()
2779 def isUSVString(self
):
2780 return self
.inner
.isUSVString()
2782 def isUTF8String(self
):
2783 return self
.inner
.isUTF8String()
2785 def isJSString(self
):
2786 return self
.inner
.isJSString()
2789 return self
.inner
.isFloat()
2791 def isUnrestricted(self
):
2792 return self
.inner
.isUnrestricted()
2794 def isInteger(self
):
2795 return self
.inner
.isInteger()
2797 def isUndefined(self
):
2798 return self
.inner
.isUndefined()
2800 def isSequence(self
):
2801 return self
.inner
.isSequence()
2804 return self
.inner
.isRecord()
2806 def isArrayBuffer(self
):
2807 return self
.inner
.isArrayBuffer()
2809 def isArrayBufferView(self
):
2810 return self
.inner
.isArrayBufferView()
2812 def isTypedArray(self
):
2813 return self
.inner
.isTypedArray()
2815 def isDictionary(self
):
2816 return self
.inner
.isDictionary()
2818 def isInterface(self
):
2819 return self
.inner
.isInterface()
2821 def isPromise(self
):
2822 # There is no such thing as a nullable Promise.
2823 assert not self
.inner
.isPromise()
2826 def isCallbackInterface(self
):
2827 return self
.inner
.isCallbackInterface()
2829 def isNonCallbackInterface(self
):
2830 return self
.inner
.isNonCallbackInterface()
2833 return self
.inner
.isEnum()
2836 return self
.inner
.isUnion()
2838 def isJSONType(self
):
2839 return self
.inner
.isJSONType()
2841 def isObservableArray(self
):
2842 return self
.inner
.isObservableArray()
2845 return self
.inner
.hasClamp()
2847 def hasEnforceRange(self
):
2848 return self
.inner
.hasEnforceRange()
2850 def hasAllowShared(self
):
2851 return self
.inner
.hasAllowShared()
2853 def isComplete(self
):
2854 return self
.name
is not None
2857 return self
.inner
.tag()
2859 def complete(self
, scope
):
2860 if not self
.inner
.isComplete():
2861 self
.inner
= self
.inner
.complete(scope
)
2862 assert self
.inner
.isComplete()
2864 if self
.inner
.nullable():
2866 "The inner type of a nullable type must not be a nullable type",
2867 [self
.location
, self
.inner
.location
],
2869 if self
.inner
.isUnion():
2870 if self
.inner
.hasNullableType
:
2872 "The inner type of a nullable type must not "
2873 "be a union type that itself has a nullable "
2874 "type as a member type",
2877 if self
.inner
.isDOMString():
2878 if self
.inner
.legacyNullToEmptyString
:
2880 "[LegacyNullToEmptyString] not allowed on a nullable DOMString",
2881 [self
.location
, self
.inner
.location
],
2883 if self
.inner
.isObservableArray():
2885 "The inner type of a nullable type must not be an ObservableArray type",
2886 [self
.location
, self
.inner
.location
],
2889 self
.name
= self
.inner
.name
+ "OrNull"
2892 def isDistinguishableFrom(self
, other
):
2895 or other
.isDictionary()
2897 other
.isUnion() and (other
.hasNullableType
or other
.hasDictionaryType())
2900 # Can't tell which type null should become
2902 return self
.inner
.isDistinguishableFrom(other
)
2904 def withExtendedAttributes(self
, attrs
):
2905 # See https://github.com/heycam/webidl/issues/827#issuecomment-565131350
2906 # Allowing extended attributes to apply to a nullable type is an intermediate solution.
2907 # A potential longer term solution is to introduce a null type and get rid of nullables.
2908 # For example, we could do `([Clamp] long or null) foo` in the future.
2909 return IDLNullableType(self
.location
, self
.inner
.withExtendedAttributes(attrs
))
2912 class IDLSequenceType(IDLParametrizedType
):
2913 def __init__(self
, location
, parameterType
):
2914 assert not parameterType
.isUndefined()
2916 IDLParametrizedType
.__init
__(self
, location
, parameterType
.name
, parameterType
)
2917 # Need to set self.name up front if our inner type is already complete,
2918 # since in that case our .complete() won't be called.
2919 if self
.inner
.isComplete():
2920 self
.name
= self
.inner
.name
+ "Sequence"
2923 return hash(self
.inner
)
2925 def __eq__(self
, other
):
2926 return isinstance(other
, IDLSequenceType
) and self
.inner
== other
.inner
2929 return self
.inner
.__str
__() + "Sequence"
2931 def prettyName(self
):
2932 return "sequence<%s>" % self
.inner
.prettyName()
2934 def isSequence(self
):
2937 def isJSONType(self
):
2938 return self
.inner
.isJSONType()
2941 return IDLType
.Tags
.sequence
2943 def complete(self
, scope
):
2944 if self
.inner
.isObservableArray():
2946 "The inner type of a sequence type must not be an ObservableArray type",
2947 [self
.location
, self
.inner
.location
],
2950 self
.inner
= self
.inner
.complete(scope
)
2951 self
.name
= self
.inner
.name
+ "Sequence"
2954 def isDistinguishableFrom(self
, other
):
2955 if other
.isPromise():
2958 # Just forward to the union; it'll deal
2959 return other
.isDistinguishableFrom(self
)
2962 or other
.isPrimitive()
2965 or other
.isInterface()
2966 or other
.isDictionary()
2967 or other
.isCallback()
2972 class IDLRecordType(IDLParametrizedType
):
2973 def __init__(self
, location
, keyType
, valueType
):
2974 assert keyType
.isString()
2975 assert keyType
.isComplete()
2977 if valueType
.isUndefined():
2979 "We don't support undefined as a Record's values' type",
2980 [location
, valueType
.location
],
2983 IDLParametrizedType
.__init
__(self
, location
, valueType
.name
, valueType
)
2984 self
.keyType
= keyType
2986 # Need to set self.name up front if our inner type is already complete,
2987 # since in that case our .complete() won't be called.
2988 if self
.inner
.isComplete():
2989 self
.name
= self
.keyType
.name
+ self
.inner
.name
+ "Record"
2992 return hash(self
.inner
)
2994 def __eq__(self
, other
):
2995 return isinstance(other
, IDLRecordType
) and self
.inner
== other
.inner
2998 return self
.keyType
.__str
__() + self
.inner
.__str
__() + "Record"
3000 def prettyName(self
):
3001 return "record<%s, %s>" % (self
.keyType
.prettyName(), self
.inner
.prettyName())
3006 def isJSONType(self
):
3007 return self
.inner
.isJSONType()
3010 return IDLType
.Tags
.record
3012 def complete(self
, scope
):
3013 if self
.inner
.isObservableArray():
3015 "The value type of a record type must not be an ObservableArray type",
3016 [self
.location
, self
.inner
.location
],
3019 self
.inner
= self
.inner
.complete(scope
)
3020 self
.name
= self
.keyType
.name
+ self
.inner
.name
+ "Record"
3024 # We do not unroll our inner. Just stop at ourselves. That
3025 # lets us add headers for both ourselves and our inner as
3029 def isDistinguishableFrom(self
, other
):
3030 if other
.isPromise():
3033 # Just forward to the union; it'll deal
3034 return other
.isDistinguishableFrom(self
)
3039 or other
.isNonCallbackInterface()
3040 or other
.isSequence()
3043 def isExposedInAllOf(self
, exposureSet
):
3044 return self
.inner
.unroll().isExposedInAllOf(exposureSet
)
3047 class IDLObservableArrayType(IDLParametrizedType
):
3048 def __init__(self
, location
, innerType
):
3049 assert not innerType
.isUndefined()
3050 IDLParametrizedType
.__init
__(self
, location
, None, innerType
)
3053 return hash(self
.inner
)
3055 def __eq__(self
, other
):
3056 return isinstance(other
, IDLObservableArrayType
) and self
.inner
== other
.inner
3059 return self
.inner
.__str
__() + "ObservableArray"
3061 def prettyName(self
):
3062 return "ObservableArray<%s>" % self
.inner
.prettyName()
3064 def isJSONType(self
):
3065 return self
.inner
.isJSONType()
3067 def isObservableArray(self
):
3070 def isComplete(self
):
3071 return self
.name
is not None
3074 return IDLType
.Tags
.observablearray
3076 def complete(self
, scope
):
3077 if not self
.inner
.isComplete():
3078 self
.inner
= self
.inner
.complete(scope
)
3079 assert self
.inner
.isComplete()
3081 if self
.inner
.isDictionary():
3083 "The inner type of an ObservableArray type must not "
3084 "be a dictionary type",
3085 [self
.location
, self
.inner
.location
],
3087 if self
.inner
.isSequence():
3089 "The inner type of an ObservableArray type must not "
3090 "be a sequence type",
3091 [self
.location
, self
.inner
.location
],
3093 if self
.inner
.isRecord():
3095 "The inner type of an ObservableArray type must not be a record type",
3096 [self
.location
, self
.inner
.location
],
3098 if self
.inner
.isObservableArray():
3100 "The inner type of an ObservableArray type must not "
3101 "be an ObservableArray type",
3102 [self
.location
, self
.inner
.location
],
3105 self
.name
= self
.inner
.name
+ "ObservableArray"
3108 def isDistinguishableFrom(self
, other
):
3109 # ObservableArrays are not distinguishable from anything.
3113 class IDLUnionType(IDLType
):
3114 def __init__(self
, location
, memberTypes
):
3115 IDLType
.__init
__(self
, location
, "")
3116 self
.memberTypes
= memberTypes
3117 self
.hasNullableType
= False
3118 self
._dictionaryType
= None
3119 self
.flatMemberTypes
= None
3120 self
.builtin
= False
3122 def __eq__(self
, other
):
3123 return isinstance(other
, IDLUnionType
) and self
.memberTypes
== other
.memberTypes
3126 assert self
.isComplete()
3127 return self
.name
.__hash
__()
3129 def prettyName(self
):
3130 return "(" + " or ".join(m
.prettyName() for m
in self
.memberTypes
) + ")"
3135 def isJSONType(self
):
3136 return all(m
.isJSONType() for m
in self
.memberTypes
)
3138 def includesRestrictedFloat(self
):
3139 return any(t
.includesRestrictedFloat() for t
in self
.memberTypes
)
3142 return IDLType
.Tags
.union
3144 def resolveType(self
, parentScope
):
3145 assert isinstance(parentScope
, IDLScope
)
3146 for t
in self
.memberTypes
:
3147 t
.resolveType(parentScope
)
3149 def isComplete(self
):
3150 return self
.flatMemberTypes
is not None
3152 def complete(self
, scope
):
3154 if isinstance(type, IDLNullableType
):
3155 return typeName(type.inner
) + "OrNull"
3156 if isinstance(type, IDLWrapperType
):
3157 return typeName(type._identifier
.object())
3158 if isinstance(type, IDLObjectWithIdentifier
):
3159 return typeName(type.identifier
)
3160 if isinstance(type, IDLBuiltinType
) and type.hasAllowShared():
3161 assert type.isBufferSource()
3162 return "MaybeShared" + type.name
3165 for i
, type in enumerate(self
.memberTypes
):
3166 if not type.isComplete():
3167 self
.memberTypes
[i
] = type.complete(scope
)
3169 self
.name
= "Or".join(typeName(type) for type in self
.memberTypes
)
3170 self
.flatMemberTypes
= list(self
.memberTypes
)
3172 while i
< len(self
.flatMemberTypes
):
3173 if self
.flatMemberTypes
[i
].nullable():
3174 if self
.hasNullableType
:
3176 "Can't have more than one nullable types in a union",
3177 [nullableType
.location
, self
.flatMemberTypes
[i
].location
],
3179 if self
.hasDictionaryType():
3181 "Can't have a nullable type and a "
3182 "dictionary type in a union",
3184 self
._dictionaryType
.location
,
3185 self
.flatMemberTypes
[i
].location
,
3188 self
.hasNullableType
= True
3189 nullableType
= self
.flatMemberTypes
[i
]
3190 self
.flatMemberTypes
[i
] = self
.flatMemberTypes
[i
].inner
3192 if self
.flatMemberTypes
[i
].isDictionary():
3193 if self
.hasNullableType
:
3195 "Can't have a nullable type and a "
3196 "dictionary type in a union",
3197 [nullableType
.location
, self
.flatMemberTypes
[i
].location
],
3199 self
._dictionaryType
= self
.flatMemberTypes
[i
]
3200 self
.flatMemberTypes
[i
].inner
.needsConversionFromJS
= True
3201 elif self
.flatMemberTypes
[i
].isUnion():
3202 self
.flatMemberTypes
[i
: i
+ 1] = self
.flatMemberTypes
[i
].memberTypes
3206 for i
, t
in enumerate(self
.flatMemberTypes
[:-1]):
3207 for u
in self
.flatMemberTypes
[i
+ 1 :]:
3208 if not t
.isDistinguishableFrom(u
):
3210 "Flat member types of a union should be "
3211 "distinguishable, " + str(t
) + " is not "
3212 "distinguishable from " + str(u
),
3213 [self
.location
, t
.location
, u
.location
],
3218 def isDistinguishableFrom(self
, other
):
3219 if self
.hasNullableType
and other
.nullable():
3220 # Can't tell which type null should become
3223 otherTypes
= other
.unroll().memberTypes
3225 otherTypes
= [other
]
3226 # For every type in otherTypes, check that it's distinguishable from
3227 # every type in our types
3228 for u
in otherTypes
:
3229 if any(not t
.isDistinguishableFrom(u
) for t
in self
.memberTypes
):
3233 def isExposedInAllOf(self
, exposureSet
):
3234 # We could have different member types in different globals.
3235 # Just make sure that each thing in exposureSet has one of our member types exposed in it.
3236 for globalName
in exposureSet
:
3238 t
.unroll().isExposedInAllOf(set([globalName
]))
3239 for t
in self
.flatMemberTypes
3244 def hasDictionaryType(self
):
3245 return self
._dictionaryType
is not None
3247 def hasPossiblyEmptyDictionaryType(self
):
3249 self
._dictionaryType
is not None and self
._dictionaryType
.inner
.canBeEmpty()
3252 def _getDependentObjects(self
):
3253 return set(self
.memberTypes
)
3256 class IDLTypedefType(IDLType
):
3257 def __init__(self
, location
, innerType
, name
):
3258 IDLType
.__init
__(self
, location
, name
)
3259 self
.inner
= innerType
3260 self
.builtin
= False
3263 return hash(self
.inner
)
3265 def __eq__(self
, other
):
3266 return isinstance(other
, IDLTypedefType
) and self
.inner
== other
.inner
3272 return self
.inner
.nullable()
3274 def isPrimitive(self
):
3275 return self
.inner
.isPrimitive()
3277 def isBoolean(self
):
3278 return self
.inner
.isBoolean()
3280 def isNumeric(self
):
3281 return self
.inner
.isNumeric()
3284 return self
.inner
.isString()
3286 def isByteString(self
):
3287 return self
.inner
.isByteString()
3289 def isDOMString(self
):
3290 return self
.inner
.isDOMString()
3292 def isUSVString(self
):
3293 return self
.inner
.isUSVString()
3295 def isUTF8String(self
):
3296 return self
.inner
.isUTF8String()
3298 def isJSString(self
):
3299 return self
.inner
.isJSString()
3301 def isUndefined(self
):
3302 return self
.inner
.isUndefined()
3304 def isJSONType(self
):
3305 return self
.inner
.isJSONType()
3307 def isSequence(self
):
3308 return self
.inner
.isSequence()
3311 return self
.inner
.isRecord()
3313 def isDictionary(self
):
3314 return self
.inner
.isDictionary()
3316 def isArrayBuffer(self
):
3317 return self
.inner
.isArrayBuffer()
3319 def isArrayBufferView(self
):
3320 return self
.inner
.isArrayBufferView()
3322 def isTypedArray(self
):
3323 return self
.inner
.isTypedArray()
3325 def isInterface(self
):
3326 return self
.inner
.isInterface()
3328 def isCallbackInterface(self
):
3329 return self
.inner
.isCallbackInterface()
3331 def isNonCallbackInterface(self
):
3332 return self
.inner
.isNonCallbackInterface()
3334 def isComplete(self
):
3337 def complete(self
, parentScope
):
3338 if not self
.inner
.isComplete():
3339 self
.inner
= self
.inner
.complete(parentScope
)
3340 assert self
.inner
.isComplete()
3343 # Do we need a resolveType impl? I don't think it's particularly useful....
3346 return self
.inner
.tag()
3349 return self
.inner
.unroll()
3351 def isDistinguishableFrom(self
, other
):
3352 return self
.inner
.isDistinguishableFrom(other
)
3354 def _getDependentObjects(self
):
3355 return self
.inner
._getDependentObjects
()
3357 def withExtendedAttributes(self
, attrs
):
3358 return IDLTypedefType(
3359 self
.location
, self
.inner
.withExtendedAttributes(attrs
), self
.name
3363 class IDLTypedef(IDLObjectWithIdentifier
):
3364 def __init__(self
, location
, parentScope
, innerType
, name
):
3365 # Set self.innerType first, because IDLObjectWithIdentifier.__init__
3366 # will call our __str__, which wants to use it.
3367 self
.innerType
= innerType
3368 identifier
= IDLUnresolvedIdentifier(location
, name
)
3369 IDLObjectWithIdentifier
.__init
__(self
, location
, parentScope
, identifier
)
3372 return "Typedef %s %s" % (self
.identifier
.name
, self
.innerType
)
3374 def finish(self
, parentScope
):
3375 if not self
.innerType
.isComplete():
3376 self
.innerType
= self
.innerType
.complete(parentScope
)
3381 def isTypedef(self
):
3384 def addExtendedAttributes(self
, attrs
):
3387 "There are no extended attributes that are " "allowed on typedefs",
3388 [attrs
[0].location
, self
.location
],
3391 def _getDependentObjects(self
):
3392 return self
.innerType
._getDependentObjects
()
3395 class IDLWrapperType(IDLType
):
3396 def __init__(self
, location
, inner
):
3397 IDLType
.__init
__(self
, location
, inner
.identifier
.name
)
3399 self
._identifier
= inner
.identifier
3400 self
.builtin
= False
3403 return hash(self
._identifier
) + hash(self
.builtin
)
3405 def __eq__(self
, other
):
3407 isinstance(other
, IDLWrapperType
)
3408 and self
._identifier
== other
._identifier
3409 and self
.builtin
== other
.builtin
3413 return str(self
.name
) + " (Wrapper)"
3415 def isDictionary(self
):
3416 return isinstance(self
.inner
, IDLDictionary
)
3418 def isInterface(self
):
3419 return isinstance(self
.inner
, IDLInterface
) or isinstance(
3420 self
.inner
, IDLExternalInterface
3423 def isCallbackInterface(self
):
3424 return self
.isInterface() and self
.inner
.isCallback()
3426 def isNonCallbackInterface(self
):
3427 return self
.isInterface() and not self
.inner
.isCallback()
3430 return isinstance(self
.inner
, IDLEnum
)
3432 def isJSONType(self
):
3433 if self
.isInterface():
3434 if self
.inner
.isExternal():
3438 if any(m
.isMethod() and m
.isToJSON() for m
in iface
.members
):
3440 iface
= iface
.parent
3444 elif self
.isDictionary():
3445 dictionary
= self
.inner
3447 if not all(m
.type.isJSONType() for m
in dictionary
.members
):
3449 dictionary
= dictionary
.parent
3453 "IDLWrapperType wraps type %s that we don't know if "
3454 "is serializable" % type(self
.inner
),
3458 def resolveType(self
, parentScope
):
3459 assert isinstance(parentScope
, IDLScope
)
3460 self
.inner
.resolve(parentScope
)
3462 def isComplete(self
):
3466 if self
.isInterface():
3467 return IDLType
.Tags
.interface
3469 return IDLType
.Tags
.enum
3470 elif self
.isDictionary():
3471 return IDLType
.Tags
.dictionary
3475 def isDistinguishableFrom(self
, other
):
3476 if other
.isPromise():
3479 # Just forward to the union; it'll deal
3480 return other
.isDistinguishableFrom(self
)
3481 assert self
.isInterface() or self
.isEnum() or self
.isDictionary()
3485 or other
.isPrimitive()
3486 or other
.isInterface()
3488 or other
.isCallback()
3489 or other
.isDictionary()
3490 or other
.isSequence()
3493 if self
.isDictionary() and (other
.nullable() or other
.isUndefined()):
3499 or other
.isSequence()
3502 if self
.isDictionary():
3503 # Callbacks without `LegacyTreatNonObjectAsNull` are distinguishable from Dictionary likes
3504 if other
.isCallback():
3505 return not other
.callback
._treatNonObjectAsNull
3506 return other
.isNonCallbackInterface()
3508 assert self
.isInterface()
3509 if other
.isInterface():
3510 if other
.isSpiderMonkeyInterface():
3511 # Just let |other| handle things
3512 return other
.isDistinguishableFrom(self
)
3513 assert self
.isGeckoInterface() and other
.isGeckoInterface()
3514 if self
.inner
.isExternal() or other
.unroll().inner
.isExternal():
3515 return self
!= other
3517 self
.inner
.interfacesBasedOnSelf
3518 & other
.unroll().inner
.interfacesBasedOnSelf
3519 ) == 0 and (self
.isNonCallbackInterface() or other
.isNonCallbackInterface())
3522 or other
.isDictionary()
3523 or other
.isCallback()
3526 return self
.isNonCallbackInterface()
3528 # Not much else |other| can be.
3529 # any is the union of all non-union types, so it's not distinguishable
3530 # from other unions (because it is a union itself), or from all
3531 # non-union types (because it has all of them as its members).
3532 assert other
.isAny() or other
.isObject()
3535 def isExposedInAllOf(self
, exposureSet
):
3536 if not self
.isInterface():
3539 if iface
.isExternal():
3540 # Let's say true, so we don't have to implement exposure mixins on
3541 # external interfaces and sprinkle [Exposed=Window] on every single
3542 # external interface declaration.
3544 return iface
.exposureSet
.issuperset(exposureSet
)
3546 def _getDependentObjects(self
):
3547 # NB: The codegen for an interface type depends on
3548 # a) That the identifier is in fact an interface (as opposed to
3549 # a dictionary or something else).
3550 # b) The native type of the interface.
3551 # If we depend on the interface object we will also depend on
3552 # anything the interface depends on which is undesirable. We
3553 # considered implementing a dependency just on the interface type
3554 # file, but then every modification to an interface would cause this
3555 # to be regenerated which is still undesirable. We decided not to
3556 # depend on anything, reasoning that:
3557 # 1) Changing the concrete type of the interface requires modifying
3558 # Bindings.conf, which is still a global dependency.
3559 # 2) Changing an interface to a dictionary (or vice versa) with the
3560 # same identifier should be incredibly rare.
3562 # On the other hand, if our type is a dictionary, we should
3563 # depend on it, because the member types of a dictionary
3564 # affect whether a method taking the dictionary as an argument
3565 # takes a JSContext* argument or not.
3566 if self
.isDictionary():
3567 return set([self
.inner
])
3571 class IDLPromiseType(IDLParametrizedType
):
3572 def __init__(self
, location
, innerType
):
3573 IDLParametrizedType
.__init
__(self
, location
, "Promise", innerType
)
3576 return hash(self
.promiseInnerType())
3578 def __eq__(self
, other
):
3580 isinstance(other
, IDLPromiseType
)
3581 and self
.promiseInnerType() == other
.promiseInnerType()
3585 return self
.inner
.__str
__() + "Promise"
3587 def prettyName(self
):
3588 return "Promise<%s>" % self
.inner
.prettyName()
3590 def isPromise(self
):
3593 def promiseInnerType(self
):
3597 return IDLType
.Tags
.promise
3599 def complete(self
, scope
):
3600 if self
.inner
.isObservableArray():
3602 "The inner type of a promise type must not be an ObservableArray type",
3603 [self
.location
, self
.inner
.location
],
3606 self
.inner
= self
.promiseInnerType().complete(scope
)
3610 # We do not unroll our inner. Just stop at ourselves. That
3611 # lets us add headers for both ourselves and our inner as
3615 def isDistinguishableFrom(self
, other
):
3616 # Promises are not distinguishable from anything.
3619 def isExposedInAllOf(self
, exposureSet
):
3620 # Check the internal type
3621 return self
.promiseInnerType().unroll().isExposedInAllOf(exposureSet
)
3624 class IDLBuiltinType(IDLType
):
3634 "unsigned_long_long",
3635 # Additional primitive types
3637 "unrestricted_float",
3639 "unrestricted_double",
3640 # IMPORTANT: "double" must be the last primitive type listed
3656 "Uint8ClampedArray",
3666 Types
.byte
: IDLType
.Tags
.int8
,
3667 Types
.octet
: IDLType
.Tags
.uint8
,
3668 Types
.short
: IDLType
.Tags
.int16
,
3669 Types
.unsigned_short
: IDLType
.Tags
.uint16
,
3670 Types
.long: IDLType
.Tags
.int32
,
3671 Types
.unsigned_long
: IDLType
.Tags
.uint32
,
3672 Types
.long_long
: IDLType
.Tags
.int64
,
3673 Types
.unsigned_long_long
: IDLType
.Tags
.uint64
,
3674 Types
.boolean
: IDLType
.Tags
.bool,
3675 Types
.unrestricted_float
: IDLType
.Tags
.unrestricted_float
,
3676 Types
.float: IDLType
.Tags
.float,
3677 Types
.unrestricted_double
: IDLType
.Tags
.unrestricted_double
,
3678 Types
.double
: IDLType
.Tags
.double
,
3679 Types
.any
: IDLType
.Tags
.any
,
3680 Types
.undefined
: IDLType
.Tags
.undefined
,
3681 Types
.domstring
: IDLType
.Tags
.domstring
,
3682 Types
.bytestring
: IDLType
.Tags
.bytestring
,
3683 Types
.usvstring
: IDLType
.Tags
.usvstring
,
3684 Types
.utf8string
: IDLType
.Tags
.utf8string
,
3685 Types
.jsstring
: IDLType
.Tags
.jsstring
,
3686 Types
.object: IDLType
.Tags
.object,
3687 Types
.ArrayBuffer
: IDLType
.Tags
.interface
,
3688 Types
.ArrayBufferView
: IDLType
.Tags
.interface
,
3689 Types
.Int8Array
: IDLType
.Tags
.interface
,
3690 Types
.Uint8Array
: IDLType
.Tags
.interface
,
3691 Types
.Uint8ClampedArray
: IDLType
.Tags
.interface
,
3692 Types
.Int16Array
: IDLType
.Tags
.interface
,
3693 Types
.Uint16Array
: IDLType
.Tags
.interface
,
3694 Types
.Int32Array
: IDLType
.Tags
.interface
,
3695 Types
.Uint32Array
: IDLType
.Tags
.interface
,
3696 Types
.Float32Array
: IDLType
.Tags
.interface
,
3697 Types
.Float64Array
: IDLType
.Tags
.interface
,
3702 Types
.octet
: "octet",
3703 Types
.short
: "short",
3704 Types
.unsigned_short
: "unsigned short",
3706 Types
.unsigned_long
: "unsigned long",
3707 Types
.long_long
: "long long",
3708 Types
.unsigned_long_long
: "unsigned long long",
3709 Types
.boolean
: "boolean",
3710 Types
.unrestricted_float
: "unrestricted float",
3711 Types
.float: "float",
3712 Types
.unrestricted_double
: "unrestricted double",
3713 Types
.double
: "double",
3715 Types
.undefined
: "undefined",
3716 Types
.domstring
: "DOMString",
3717 Types
.bytestring
: "ByteString",
3718 Types
.usvstring
: "USVString",
3719 Types
.utf8string
: "USVString", # That's what it is in spec terms
3720 Types
.jsstring
: "USVString", # Again, that's what it is in spec terms
3721 Types
.object: "object",
3722 Types
.ArrayBuffer
: "ArrayBuffer",
3723 Types
.ArrayBufferView
: "ArrayBufferView",
3724 Types
.Int8Array
: "Int8Array",
3725 Types
.Uint8Array
: "Uint8Array",
3726 Types
.Uint8ClampedArray
: "Uint8ClampedArray",
3727 Types
.Int16Array
: "Int16Array",
3728 Types
.Uint16Array
: "Uint16Array",
3729 Types
.Int32Array
: "Int32Array",
3730 Types
.Uint32Array
: "Uint32Array",
3731 Types
.Float32Array
: "Float32Array",
3732 Types
.Float64Array
: "Float64Array",
3742 legacyNullToEmptyString
=False,
3747 The mutually exclusive clamp/enforceRange/legacyNullToEmptyString/allowShared arguments
3748 are used to create instances of this type with the appropriate attributes attached. Use
3749 .clamped(), .rangeEnforced(), .withLegacyNullToEmptyString() and .withAllowShared().
3751 attrLocation is an array of source locations of these attributes for error reporting.
3753 IDLType
.__init
__(self
, location
, name
)
3755 self
._typeTag
= type
3756 self
._clamped
= None
3757 self
._rangeEnforced
= None
3758 self
._withLegacyNullToEmptyString
= None
3759 self
._withAllowShared
= None
3760 if self
.isInteger():
3763 self
.name
= "Clamped" + self
.name
3764 self
._extendedAttrDict
["Clamp"] = True
3766 self
._enforceRange
= True
3767 self
.name
= "RangeEnforced" + self
.name
3768 self
._extendedAttrDict
["EnforceRange"] = True
3769 elif clamp
or enforceRange
:
3771 "Non-integer types cannot be [Clamp] or [EnforceRange]", attrLocation
3773 if self
.isDOMString() or self
.isUTF8String():
3774 if legacyNullToEmptyString
:
3775 self
.legacyNullToEmptyString
= True
3776 self
.name
= "NullIsEmpty" + self
.name
3777 self
._extendedAttrDict
["LegacyNullToEmptyString"] = True
3778 elif legacyNullToEmptyString
:
3780 "Non-string types cannot be [LegacyNullToEmptyString]", attrLocation
3782 if self
.isBufferSource():
3784 self
._allowShared
= True
3785 self
._extendedAttrDict
["AllowShared"] = True
3788 "Types that are not buffer source types cannot be [AllowShared]",
3793 if self
._allowShared
:
3794 assert self
.isBufferSource()
3795 return "MaybeShared" + str(self
.name
)
3796 return str(self
.name
)
3798 def prettyName(self
):
3799 return IDLBuiltinType
.PrettyNames
[self
._typeTag
]
3801 def clamped(self
, attrLocation
):
3802 if not self
._clamped
:
3803 self
._clamped
= IDLBuiltinType(
3808 attrLocation
=attrLocation
,
3810 return self
._clamped
3812 def rangeEnforced(self
, attrLocation
):
3813 if not self
._rangeEnforced
:
3814 self
._rangeEnforced
= IDLBuiltinType(
3819 attrLocation
=attrLocation
,
3821 return self
._rangeEnforced
3823 def withLegacyNullToEmptyString(self
, attrLocation
):
3824 if not self
._withLegacyNullToEmptyString
:
3825 self
._withLegacyNullToEmptyString
= IDLBuiltinType(
3829 legacyNullToEmptyString
=True,
3830 attrLocation
=attrLocation
,
3832 return self
._withLegacyNullToEmptyString
3834 def withAllowShared(self
, attrLocation
):
3835 if not self
._withAllowShared
:
3836 self
._withAllowShared
= IDLBuiltinType(
3841 attrLocation
=attrLocation
,
3843 return self
._withAllowShared
3845 def isPrimitive(self
):
3846 return self
._typeTag
<= IDLBuiltinType
.Types
.double
3848 def isBoolean(self
):
3849 return self
._typeTag
== IDLBuiltinType
.Types
.boolean
3851 def isUndefined(self
):
3852 return self
._typeTag
== IDLBuiltinType
.Types
.undefined
3854 def isNumeric(self
):
3855 return self
.isPrimitive() and not self
.isBoolean()
3859 self
._typeTag
== IDLBuiltinType
.Types
.domstring
3860 or self
._typeTag
== IDLBuiltinType
.Types
.bytestring
3861 or self
._typeTag
== IDLBuiltinType
.Types
.usvstring
3862 or self
._typeTag
== IDLBuiltinType
.Types
.utf8string
3863 or self
._typeTag
== IDLBuiltinType
.Types
.jsstring
3866 def isByteString(self
):
3867 return self
._typeTag
== IDLBuiltinType
.Types
.bytestring
3869 def isDOMString(self
):
3870 return self
._typeTag
== IDLBuiltinType
.Types
.domstring
3872 def isUSVString(self
):
3873 return self
._typeTag
== IDLBuiltinType
.Types
.usvstring
3875 def isUTF8String(self
):
3876 return self
._typeTag
== IDLBuiltinType
.Types
.utf8string
3878 def isJSString(self
):
3879 return self
._typeTag
== IDLBuiltinType
.Types
.jsstring
3881 def isInteger(self
):
3882 return self
._typeTag
<= IDLBuiltinType
.Types
.unsigned_long_long
3884 def isArrayBuffer(self
):
3885 return self
._typeTag
== IDLBuiltinType
.Types
.ArrayBuffer
3887 def isArrayBufferView(self
):
3888 return self
._typeTag
== IDLBuiltinType
.Types
.ArrayBufferView
3890 def isTypedArray(self
):
3892 self
._typeTag
>= IDLBuiltinType
.Types
.Int8Array
3893 and self
._typeTag
<= IDLBuiltinType
.Types
.Float64Array
3896 def isInterface(self
):
3897 # TypedArray things are interface types per the TypedArray spec,
3898 # but we handle them as builtins because SpiderMonkey implements
3899 # all of it internally.
3900 return self
.isArrayBuffer() or self
.isArrayBufferView() or self
.isTypedArray()
3902 def isNonCallbackInterface(self
):
3903 # All the interfaces we can be are non-callback
3904 return self
.isInterface()
3908 self
._typeTag
== IDLBuiltinType
.Types
.float
3909 or self
._typeTag
== IDLBuiltinType
.Types
.double
3910 or self
._typeTag
== IDLBuiltinType
.Types
.unrestricted_float
3911 or self
._typeTag
== IDLBuiltinType
.Types
.unrestricted_double
3914 def isUnrestricted(self
):
3915 assert self
.isFloat()
3917 self
._typeTag
== IDLBuiltinType
.Types
.unrestricted_float
3918 or self
._typeTag
== IDLBuiltinType
.Types
.unrestricted_double
3921 def isJSONType(self
):
3922 return self
.isPrimitive() or self
.isString() or self
.isObject()
3924 def includesRestrictedFloat(self
):
3925 return self
.isFloat() and not self
.isUnrestricted()
3928 return IDLBuiltinType
.TagLookup
[self
._typeTag
]
3930 def isDistinguishableFrom(self
, other
):
3931 if other
.isPromise():
3934 # Just forward to the union; it'll deal
3935 return other
.isDistinguishableFrom(self
)
3936 if self
.isUndefined():
3937 return not (other
.isUndefined() or other
.isDictionaryLike())
3938 if self
.isPrimitive():
3943 or other
.isInterface()
3945 or other
.isCallback()
3946 or other
.isDictionary()
3947 or other
.isSequence()
3951 if self
.isBoolean():
3952 return other
.isNumeric()
3953 assert self
.isNumeric()
3954 return other
.isBoolean()
3958 or other
.isPrimitive()
3959 or other
.isInterface()
3961 or other
.isCallback()
3962 or other
.isDictionary()
3963 or other
.isSequence()
3967 # Can't tell "any" apart from anything
3972 or other
.isPrimitive()
3976 # Not much else we could be!
3977 assert self
.isSpiderMonkeyInterface()
3978 # Like interfaces, but we know we're not a callback
3981 or other
.isPrimitive()
3984 or other
.isCallback()
3985 or other
.isDictionary()
3986 or other
.isSequence()
3991 # ArrayBuffer is distinguishable from everything
3992 # that's not an ArrayBuffer or a callback interface
3993 (self
.isArrayBuffer() and not other
.isArrayBuffer())
3995 # ArrayBufferView is distinguishable from everything
3996 # that's not an ArrayBufferView or typed array.
3998 self
.isArrayBufferView()
3999 and not other
.isArrayBufferView()
4000 and not other
.isTypedArray()
4003 # Typed arrays are distinguishable from everything
4004 # except ArrayBufferView and the same type of typed
4008 and not other
.isArrayBufferView()
4009 and not (other
.isTypedArray() and other
.name
== self
.name
)
4015 def _getDependentObjects(self
):
4018 def withExtendedAttributes(self
, attrs
):
4020 for attribute
in attrs
:
4021 identifier
= attribute
.identifier()
4022 if identifier
== "Clamp":
4023 if not attribute
.noArguments():
4025 "[Clamp] must take no arguments", [attribute
.location
]
4027 if ret
.hasEnforceRange() or self
._enforceRange
:
4029 "[EnforceRange] and [Clamp] are mutually exclusive",
4030 [self
.location
, attribute
.location
],
4032 ret
= self
.clamped([self
.location
, attribute
.location
])
4033 elif identifier
== "EnforceRange":
4034 if not attribute
.noArguments():
4036 "[EnforceRange] must take no arguments", [attribute
.location
]
4038 if ret
.hasClamp() or self
._clamp
:
4040 "[EnforceRange] and [Clamp] are mutually exclusive",
4041 [self
.location
, attribute
.location
],
4043 ret
= self
.rangeEnforced([self
.location
, attribute
.location
])
4044 elif identifier
== "LegacyNullToEmptyString":
4045 if not (self
.isDOMString() or self
.isUTF8String()):
4047 "[LegacyNullToEmptyString] only allowed on DOMStrings and UTF8Strings",
4048 [self
.location
, attribute
.location
],
4050 assert not self
.nullable()
4051 if attribute
.hasValue():
4053 "[LegacyNullToEmptyString] must take no identifier argument",
4054 [attribute
.location
],
4056 ret
= self
.withLegacyNullToEmptyString(
4057 [self
.location
, attribute
.location
]
4059 elif identifier
== "AllowShared":
4060 if not attribute
.noArguments():
4062 "[AllowShared] must take no arguments", [attribute
.location
]
4064 if not self
.isBufferSource():
4066 "[AllowShared] only allowed on buffer source types",
4067 [self
.location
, attribute
.location
],
4069 ret
= self
.withAllowShared([self
.location
, attribute
.location
])
4073 "Unhandled extended attribute on type",
4074 [self
.location
, attribute
.location
],
4080 IDLBuiltinType
.Types
.byte
: IDLBuiltinType(
4081 BuiltinLocation("<builtin type>"), "Byte", IDLBuiltinType
.Types
.byte
4083 IDLBuiltinType
.Types
.octet
: IDLBuiltinType(
4084 BuiltinLocation("<builtin type>"), "Octet", IDLBuiltinType
.Types
.octet
4086 IDLBuiltinType
.Types
.short
: IDLBuiltinType(
4087 BuiltinLocation("<builtin type>"), "Short", IDLBuiltinType
.Types
.short
4089 IDLBuiltinType
.Types
.unsigned_short
: IDLBuiltinType(
4090 BuiltinLocation("<builtin type>"),
4092 IDLBuiltinType
.Types
.unsigned_short
,
4094 IDLBuiltinType
.Types
.long: IDLBuiltinType(
4095 BuiltinLocation("<builtin type>"), "Long", IDLBuiltinType
.Types
.long
4097 IDLBuiltinType
.Types
.unsigned_long
: IDLBuiltinType(
4098 BuiltinLocation("<builtin type>"),
4100 IDLBuiltinType
.Types
.unsigned_long
,
4102 IDLBuiltinType
.Types
.long_long
: IDLBuiltinType(
4103 BuiltinLocation("<builtin type>"), "LongLong", IDLBuiltinType
.Types
.long_long
4105 IDLBuiltinType
.Types
.unsigned_long_long
: IDLBuiltinType(
4106 BuiltinLocation("<builtin type>"),
4108 IDLBuiltinType
.Types
.unsigned_long_long
,
4110 IDLBuiltinType
.Types
.undefined
: IDLBuiltinType(
4111 BuiltinLocation("<builtin type>"), "Undefined", IDLBuiltinType
.Types
.undefined
4113 IDLBuiltinType
.Types
.boolean
: IDLBuiltinType(
4114 BuiltinLocation("<builtin type>"), "Boolean", IDLBuiltinType
.Types
.boolean
4116 IDLBuiltinType
.Types
.float: IDLBuiltinType(
4117 BuiltinLocation("<builtin type>"), "Float", IDLBuiltinType
.Types
.float
4119 IDLBuiltinType
.Types
.unrestricted_float
: IDLBuiltinType(
4120 BuiltinLocation("<builtin type>"),
4121 "UnrestrictedFloat",
4122 IDLBuiltinType
.Types
.unrestricted_float
,
4124 IDLBuiltinType
.Types
.double
: IDLBuiltinType(
4125 BuiltinLocation("<builtin type>"), "Double", IDLBuiltinType
.Types
.double
4127 IDLBuiltinType
.Types
.unrestricted_double
: IDLBuiltinType(
4128 BuiltinLocation("<builtin type>"),
4129 "UnrestrictedDouble",
4130 IDLBuiltinType
.Types
.unrestricted_double
,
4132 IDLBuiltinType
.Types
.any
: IDLBuiltinType(
4133 BuiltinLocation("<builtin type>"), "Any", IDLBuiltinType
.Types
.any
4135 IDLBuiltinType
.Types
.domstring
: IDLBuiltinType(
4136 BuiltinLocation("<builtin type>"), "String", IDLBuiltinType
.Types
.domstring
4138 IDLBuiltinType
.Types
.bytestring
: IDLBuiltinType(
4139 BuiltinLocation("<builtin type>"), "ByteString", IDLBuiltinType
.Types
.bytestring
4141 IDLBuiltinType
.Types
.usvstring
: IDLBuiltinType(
4142 BuiltinLocation("<builtin type>"), "USVString", IDLBuiltinType
.Types
.usvstring
4144 IDLBuiltinType
.Types
.utf8string
: IDLBuiltinType(
4145 BuiltinLocation("<builtin type>"), "UTF8String", IDLBuiltinType
.Types
.utf8string
4147 IDLBuiltinType
.Types
.jsstring
: IDLBuiltinType(
4148 BuiltinLocation("<builtin type>"), "JSString", IDLBuiltinType
.Types
.jsstring
4150 IDLBuiltinType
.Types
.object: IDLBuiltinType(
4151 BuiltinLocation("<builtin type>"), "Object", IDLBuiltinType
.Types
.object
4153 IDLBuiltinType
.Types
.ArrayBuffer
: IDLBuiltinType(
4154 BuiltinLocation("<builtin type>"),
4156 IDLBuiltinType
.Types
.ArrayBuffer
,
4158 IDLBuiltinType
.Types
.ArrayBufferView
: IDLBuiltinType(
4159 BuiltinLocation("<builtin type>"),
4161 IDLBuiltinType
.Types
.ArrayBufferView
,
4163 IDLBuiltinType
.Types
.Int8Array
: IDLBuiltinType(
4164 BuiltinLocation("<builtin type>"), "Int8Array", IDLBuiltinType
.Types
.Int8Array
4166 IDLBuiltinType
.Types
.Uint8Array
: IDLBuiltinType(
4167 BuiltinLocation("<builtin type>"), "Uint8Array", IDLBuiltinType
.Types
.Uint8Array
4169 IDLBuiltinType
.Types
.Uint8ClampedArray
: IDLBuiltinType(
4170 BuiltinLocation("<builtin type>"),
4171 "Uint8ClampedArray",
4172 IDLBuiltinType
.Types
.Uint8ClampedArray
,
4174 IDLBuiltinType
.Types
.Int16Array
: IDLBuiltinType(
4175 BuiltinLocation("<builtin type>"), "Int16Array", IDLBuiltinType
.Types
.Int16Array
4177 IDLBuiltinType
.Types
.Uint16Array
: IDLBuiltinType(
4178 BuiltinLocation("<builtin type>"),
4180 IDLBuiltinType
.Types
.Uint16Array
,
4182 IDLBuiltinType
.Types
.Int32Array
: IDLBuiltinType(
4183 BuiltinLocation("<builtin type>"), "Int32Array", IDLBuiltinType
.Types
.Int32Array
4185 IDLBuiltinType
.Types
.Uint32Array
: IDLBuiltinType(
4186 BuiltinLocation("<builtin type>"),
4188 IDLBuiltinType
.Types
.Uint32Array
,
4190 IDLBuiltinType
.Types
.Float32Array
: IDLBuiltinType(
4191 BuiltinLocation("<builtin type>"),
4193 IDLBuiltinType
.Types
.Float32Array
,
4195 IDLBuiltinType
.Types
.Float64Array
: IDLBuiltinType(
4196 BuiltinLocation("<builtin type>"),
4198 IDLBuiltinType
.Types
.Float64Array
,
4203 integerTypeSizes
= {
4204 IDLBuiltinType
.Types
.byte
: (-128, 127),
4205 IDLBuiltinType
.Types
.octet
: (0, 255),
4206 IDLBuiltinType
.Types
.short
: (-32768, 32767),
4207 IDLBuiltinType
.Types
.unsigned_short
: (0, 65535),
4208 IDLBuiltinType
.Types
.long: (-2147483648, 2147483647),
4209 IDLBuiltinType
.Types
.unsigned_long
: (0, 4294967295),
4210 IDLBuiltinType
.Types
.long_long
: (-9223372036854775808, 9223372036854775807),
4211 IDLBuiltinType
.Types
.unsigned_long_long
: (0, 18446744073709551615),
4215 def matchIntegerValueToType(value
):
4216 for type, extremes
in integerTypeSizes
.items():
4217 (min, max) = extremes
4218 if value
<= max and value
>= min:
4219 return BuiltinTypes
[type]
4224 class NoCoercionFoundError(WebIDLError
):
4226 A class we use to indicate generic coercion failures because none of the
4227 types worked out in IDLValue.coerceToType.
4231 class IDLValue(IDLObject
):
4232 def __init__(self
, location
, type, value
):
4233 IDLObject
.__init
__(self
, location
)
4235 assert isinstance(type, IDLType
)
4239 def coerceToType(self
, type, location
):
4240 if type == self
.type:
4241 return self
# Nothing to do
4243 # We first check for unions to ensure that even if the union is nullable
4244 # we end up with the right flat member type, not the union's type.
4246 # We use the flat member types here, because if we have a nullable
4247 # member type, or a nested union, we want the type the value
4248 # actually coerces to, not the nullable or nested union type.
4249 for subtype
in type.unroll().flatMemberTypes
:
4251 coercedValue
= self
.coerceToType(subtype
, location
)
4252 # Create a new IDLValue to make sure that we have the
4253 # correct float/double type. This is necessary because we
4254 # use the value's type when it is a default value of a
4255 # union, and the union cares about the exact float type.
4256 return IDLValue(self
.location
, subtype
, coercedValue
.value
)
4257 except Exception as e
:
4258 # Make sure to propagate out WebIDLErrors that are not the
4259 # generic "hey, we could not coerce to this type at all"
4260 # exception, because those are specific "coercion failed for
4261 # reason X" exceptions. Note that we want to swallow
4262 # non-WebIDLErrors here, because those can just happen if
4263 # "type" is not something that can have a default value at
4265 if isinstance(e
, WebIDLError
) and not isinstance(
4266 e
, NoCoercionFoundError
4270 # If the type allows null, rerun this matching on the inner type, except
4271 # nullable enums. We handle those specially, because we want our
4272 # default string values to stay strings even when assigned to a nullable
4274 elif type.nullable() and not type.isEnum():
4275 innerValue
= self
.coerceToType(type.inner
, location
)
4276 return IDLValue(self
.location
, type, innerValue
.value
)
4278 elif self
.type.isInteger() and type.isInteger():
4279 # We're both integer types. See if we fit.
4281 (min, max) = integerTypeSizes
[type._typeTag
]
4282 if self
.value
<= max and self
.value
>= min:
4284 return IDLValue(self
.location
, type, self
.value
)
4287 "Value %s is out of range for type %s." % (self
.value
, type),
4290 elif self
.type.isInteger() and type.isFloat():
4291 # Convert an integer literal into float
4292 if -(2**24) <= self
.value
<= 2**24:
4293 return IDLValue(self
.location
, type, float(self
.value
))
4296 "Converting value %s to %s will lose precision."
4297 % (self
.value
, type),
4300 elif self
.type.isString() and type.isEnum():
4301 # Just keep our string, but make sure it's a valid value for this enum
4302 enum
= type.unroll().inner
4303 if self
.value
not in enum
.values():
4305 "'%s' is not a valid default value for enum %s"
4306 % (self
.value
, enum
.identifier
.name
),
4307 [location
, enum
.location
],
4310 elif self
.type.isFloat() and type.isFloat():
4311 if not type.isUnrestricted() and (
4312 self
.value
== float("inf")
4313 or self
.value
== float("-inf")
4314 or math
.isnan(self
.value
)
4317 "Trying to convert unrestricted value %s to non-unrestricted"
4321 return IDLValue(self
.location
, type, self
.value
)
4322 elif self
.type.isString() and type.isUSVString():
4323 # Allow USVStrings to use default value just like
4324 # DOMString. No coercion is required in this case as Codegen.py
4325 # treats USVString just like DOMString, but with an
4326 # extra normalization step.
4327 assert self
.type.isDOMString()
4329 elif self
.type.isString() and (
4330 type.isByteString() or type.isJSString() or type.isUTF8String()
4332 # Allow ByteStrings, UTF8String, and JSStrings to use a default
4333 # value like DOMString.
4334 # No coercion is required as Codegen.py will handle the
4335 # extra steps. We want to make sure that our string contains
4336 # only valid characters, so we check that here.
4338 " " + string
.ascii_letters
+ string
.digits
+ string
.punctuation
4340 for idx
, c
in enumerate(self
.value
):
4341 if c
not in valid_ascii_lit
:
4343 "Coercing this string literal %s to a ByteString is not supported yet. "
4344 "Coercion failed due to an unsupported byte %d at index %d."
4345 % (self
.value
.__repr
__(), ord(c
), idx
),
4349 return IDLValue(self
.location
, type, self
.value
)
4350 elif self
.type.isDOMString() and type.legacyNullToEmptyString
:
4351 # LegacyNullToEmptyString is a different type for resolution reasons,
4352 # however once you have a value it doesn't matter
4355 raise NoCoercionFoundError(
4356 "Cannot coerce type %s to type %s." % (self
.type, type), [location
]
4359 def _getDependentObjects(self
):
4363 class IDLNullValue(IDLObject
):
4364 def __init__(self
, location
):
4365 IDLObject
.__init
__(self
, location
)
4369 def coerceToType(self
, type, location
):
4371 not isinstance(type, IDLNullableType
)
4372 and not (type.isUnion() and type.hasNullableType
)
4373 and not type.isAny()
4375 raise WebIDLError("Cannot coerce null value to type %s." % type, [location
])
4377 nullValue
= IDLNullValue(self
.location
)
4378 if type.isUnion() and not type.nullable() and type.hasDictionaryType():
4379 # We're actually a default value for the union's dictionary member.
4381 for t
in type.flatMemberTypes
:
4382 if t
.isDictionary():
4385 nullValue
.type = type
4388 def _getDependentObjects(self
):
4392 class IDLEmptySequenceValue(IDLObject
):
4393 def __init__(self
, location
):
4394 IDLObject
.__init
__(self
, location
)
4398 def coerceToType(self
, type, location
):
4400 # We use the flat member types here, because if we have a nullable
4401 # member type, or a nested union, we want the type the value
4402 # actually coerces to, not the nullable or nested union type.
4403 for subtype
in type.unroll().flatMemberTypes
:
4405 return self
.coerceToType(subtype
, location
)
4409 if not type.isSequence():
4411 "Cannot coerce empty sequence value to type %s." % type, [location
]
4414 emptySequenceValue
= IDLEmptySequenceValue(self
.location
)
4415 emptySequenceValue
.type = type
4416 return emptySequenceValue
4418 def _getDependentObjects(self
):
4422 class IDLDefaultDictionaryValue(IDLObject
):
4423 def __init__(self
, location
):
4424 IDLObject
.__init
__(self
, location
)
4428 def coerceToType(self
, type, location
):
4430 # We use the flat member types here, because if we have a nullable
4431 # member type, or a nested union, we want the type the value
4432 # actually coerces to, not the nullable or nested union type.
4433 for subtype
in type.unroll().flatMemberTypes
:
4435 return self
.coerceToType(subtype
, location
)
4439 if not type.isDictionary():
4441 "Cannot coerce default dictionary value to type %s." % type, [location
]
4444 defaultDictionaryValue
= IDLDefaultDictionaryValue(self
.location
)
4445 defaultDictionaryValue
.type = type
4446 return defaultDictionaryValue
4448 def _getDependentObjects(self
):
4452 class IDLUndefinedValue(IDLObject
):
4453 def __init__(self
, location
):
4454 IDLObject
.__init
__(self
, location
)
4458 def coerceToType(self
, type, location
):
4459 if not type.isAny():
4461 "Cannot coerce undefined value to type %s." % type, [location
]
4464 undefinedValue
= IDLUndefinedValue(self
.location
)
4465 undefinedValue
.type = type
4466 return undefinedValue
4468 def _getDependentObjects(self
):
4472 class IDLInterfaceMember(IDLObjectWithIdentifier
, IDLExposureMixins
):
4474 "Const", "Attr", "Method", "MaplikeOrSetlike", "AsyncIterable", "Iterable"
4477 Special
= enum("Static", "Stringifier")
4479 AffectsValues
= ("Nothing", "Everything")
4480 DependsOnValues
= ("Nothing", "DOMState", "DeviceState", "Everything")
4482 def __init__(self
, location
, identifier
, tag
, extendedAttrDict
=None):
4483 IDLObjectWithIdentifier
.__init
__(self
, location
, None, identifier
)
4484 IDLExposureMixins
.__init
__(self
, location
)
4486 if extendedAttrDict
is None:
4487 self
._extendedAttrDict
= {}
4489 self
._extendedAttrDict
= extendedAttrDict
4492 return self
.tag
== IDLInterfaceMember
.Tags
.Method
4495 return self
.tag
== IDLInterfaceMember
.Tags
.Attr
4498 return self
.tag
== IDLInterfaceMember
.Tags
.Const
4500 def isMaplikeOrSetlikeOrIterable(self
):
4502 self
.tag
== IDLInterfaceMember
.Tags
.MaplikeOrSetlike
4503 or self
.tag
== IDLInterfaceMember
.Tags
.AsyncIterable
4504 or self
.tag
== IDLInterfaceMember
.Tags
.Iterable
4507 def isMaplikeOrSetlike(self
):
4508 return self
.tag
== IDLInterfaceMember
.Tags
.MaplikeOrSetlike
4510 def addExtendedAttributes(self
, attrs
):
4512 self
.handleExtendedAttribute(attr
)
4513 attrlist
= attr
.listValue()
4514 self
._extendedAttrDict
[attr
.identifier()] = (
4515 attrlist
if len(attrlist
) else True
4518 def handleExtendedAttribute(self
, attr
):
4521 def getExtendedAttribute(self
, name
):
4522 return self
._extendedAttrDict
.get(name
, None)
4524 def finish(self
, scope
):
4525 IDLExposureMixins
.finish(self
, scope
)
4528 if self
.isAttr() or self
.isMethod():
4529 if self
.affects
== "Everything" and self
.dependsOn
!= "Everything":
4531 "Interface member is flagged as affecting "
4532 "everything but not depending on everything. "
4533 "That seems rather unlikely.",
4537 if self
.getExtendedAttribute("NewObject"):
4538 if self
.dependsOn
== "Nothing" or self
.dependsOn
== "DOMState":
4540 "A [NewObject] method is not idempotent, "
4541 "so it has to depend on something other than DOM state.",
4544 if self
.getExtendedAttribute("Cached") or self
.getExtendedAttribute(
4548 "A [NewObject] attribute shouldnt be "
4549 "[Cached] or [StoreInSlot], since the point "
4550 "of those is to keep returning the same "
4551 "thing across multiple calls, which is not "
4552 "what [NewObject] does.",
4556 def _setDependsOn(self
, dependsOn
):
4557 if self
.dependsOn
!= "Everything":
4559 "Trying to specify multiple different DependsOn, "
4560 "Pure, or Constant extended attributes for "
4564 if dependsOn
not in IDLInterfaceMember
.DependsOnValues
:
4566 "Invalid [DependsOn=%s] on attribute" % dependsOn
, [self
.location
]
4568 self
.dependsOn
= dependsOn
4570 def _setAffects(self
, affects
):
4571 if self
.affects
!= "Everything":
4573 "Trying to specify multiple different Affects, "
4574 "Pure, or Constant extended attributes for "
4578 if affects
not in IDLInterfaceMember
.AffectsValues
:
4580 "Invalid [Affects=%s] on attribute" % affects
, [self
.location
]
4582 self
.affects
= affects
4584 def _addAlias(self
, alias
):
4585 if alias
in self
.aliases
:
4587 "Duplicate [Alias=%s] on attribute" % alias
, [self
.location
]
4589 self
.aliases
.append(alias
)
4591 def _addBindingAlias(self
, bindingAlias
):
4592 if bindingAlias
in self
.bindingAliases
:
4594 "Duplicate [BindingAlias=%s] on attribute" % bindingAlias
,
4597 self
.bindingAliases
.append(bindingAlias
)
4600 class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember
):
4601 def __init__(self
, location
, identifier
, ifaceType
, keyType
, valueType
, ifaceKind
):
4602 IDLInterfaceMember
.__init
__(self
, location
, identifier
, ifaceKind
)
4603 if keyType
is not None:
4604 assert isinstance(keyType
, IDLType
)
4606 assert valueType
is not None
4607 assert ifaceType
in ["maplike", "setlike", "iterable", "asynciterable"]
4608 if valueType
is not None:
4609 assert isinstance(valueType
, IDLType
)
4610 self
.keyType
= keyType
4611 self
.valueType
= valueType
4612 self
.maplikeOrSetlikeOrIterableType
= ifaceType
4613 self
.disallowedMemberNames
= []
4614 self
.disallowedNonMethodNames
= []
4616 def isMaplike(self
):
4617 return self
.maplikeOrSetlikeOrIterableType
== "maplike"
4619 def isSetlike(self
):
4620 return self
.maplikeOrSetlikeOrIterableType
== "setlike"
4622 def isIterable(self
):
4623 return self
.maplikeOrSetlikeOrIterableType
== "iterable"
4625 def isAsyncIterable(self
):
4626 return self
.maplikeOrSetlikeOrIterableType
== "asynciterable"
4628 def hasKeyType(self
):
4629 return self
.keyType
is not None
4631 def hasValueType(self
):
4632 return self
.valueType
is not None
4634 def checkCollisions(self
, members
, isAncestor
):
4635 for member
in members
:
4636 # Check that there are no disallowed members
4637 if member
.identifier
.name
in self
.disallowedMemberNames
and not (
4641 member
.isStatic() or member
.isMaplikeOrSetlikeOrIterableMethod()
4644 or (member
.isAttr() and member
.isMaplikeOrSetlikeAttr())
4647 "Member '%s' conflicts "
4648 "with reserved %s name."
4649 % (member
.identifier
.name
, self
.maplikeOrSetlikeOrIterableType
),
4650 [self
.location
, member
.location
],
4652 # Check that there are no disallowed non-method members.
4653 # Ancestor members are always disallowed here; own members
4654 # are disallowed only if they're non-methods.
4656 isAncestor
or member
.isAttr() or member
.isConst()
4657 ) and member
.identifier
.name
in self
.disallowedNonMethodNames
:
4659 "Member '%s' conflicts "
4660 "with reserved %s method."
4661 % (member
.identifier
.name
, self
.maplikeOrSetlikeOrIterableType
),
4662 [self
.location
, member
.location
],
4669 allowExistingOperations
,
4674 affectsNothing
=False,
4676 isIteratorAlias
=False,
4679 Create an IDLMethod based on the parameters passed in.
4681 - members is the member list to add this function to, since this is
4682 called during the member expansion portion of interface object
4685 - chromeOnly is only True for read-only js implemented classes, to
4686 implement underscore prefixed convenience functions which would
4687 otherwise not be available, unlike the case of C++ bindings.
4689 - isPure is only True for idempotent functions, so it is not valid for
4690 things like keys, values, etc. that return a new object every time.
4692 - affectsNothing means that nothing changes due to this method, which
4693 affects JIT optimization behavior
4695 - newObject means the method creates and returns a new object.
4698 # Only add name to lists for collision checks if it's not chrome
4703 if not allowExistingOperations
:
4704 self
.disallowedMemberNames
.append(name
)
4706 self
.disallowedNonMethodNames
.append(name
)
4707 # If allowExistingOperations is True, and another operation exists
4708 # with the same name as the one we're trying to add, don't add the
4709 # maplike/setlike operation.
4710 if allowExistingOperations
:
4712 if m
.identifier
.name
== name
and m
.isMethod() and not m
.isStatic():
4716 IDLUnresolvedIdentifier(
4717 self
.location
, name
, allowDoubleUnderscore
=chromeOnly
4721 maplikeOrSetlikeOrIterable
=self
,
4723 # We need to be able to throw from declaration methods
4724 method
.addExtendedAttributes([IDLExtendedAttribute(self
.location
, ("Throws",))])
4726 method
.addExtendedAttributes(
4727 [IDLExtendedAttribute(self
.location
, ("ChromeOnly",))]
4730 method
.addExtendedAttributes(
4731 [IDLExtendedAttribute(self
.location
, ("Pure",))]
4733 # Following attributes are used for keys/values/entries. Can't mark
4734 # them pure, since they return a new object each time they are run.
4736 method
.addExtendedAttributes(
4738 IDLExtendedAttribute(self
.location
, ("DependsOn", "Everything")),
4739 IDLExtendedAttribute(self
.location
, ("Affects", "Nothing")),
4743 method
.addExtendedAttributes(
4744 [IDLExtendedAttribute(self
.location
, ("NewObject",))]
4747 if not self
.isAsyncIterable():
4748 method
.addExtendedAttributes(
4749 [IDLExtendedAttribute(self
.location
, ("Alias", "@@iterator"))]
4752 method
.addExtendedAttributes(
4753 [IDLExtendedAttribute(self
.location
, ("Alias", "@@asyncIterator"))]
4755 members
.append(method
)
4757 def resolve(self
, parentScope
):
4759 self
.keyType
.resolveType(parentScope
)
4761 self
.valueType
.resolveType(parentScope
)
4763 def finish(self
, scope
):
4764 IDLInterfaceMember
.finish(self
, scope
)
4765 if self
.keyType
and not self
.keyType
.isComplete():
4766 t
= self
.keyType
.complete(scope
)
4768 assert not isinstance(t
, IDLUnresolvedType
)
4769 assert not isinstance(t
, IDLTypedefType
)
4770 assert not isinstance(t
.name
, IDLUnresolvedIdentifier
)
4772 if self
.valueType
and not self
.valueType
.isComplete():
4773 t
= self
.valueType
.complete(scope
)
4775 assert not isinstance(t
, IDLUnresolvedType
)
4776 assert not isinstance(t
, IDLTypedefType
)
4777 assert not isinstance(t
.name
, IDLUnresolvedIdentifier
)
4781 IDLInterfaceMember
.validate(self
)
4783 def handleExtendedAttribute(self
, attr
):
4784 IDLInterfaceMember
.handleExtendedAttribute(self
, attr
)
4786 def _getDependentObjects(self
):
4789 deps
.add(self
.keyType
)
4791 deps
.add(self
.valueType
)
4794 def getForEachArguments(self
):
4798 IDLUnresolvedIdentifier(
4799 BuiltinLocation("<auto-generated-identifier>"), "callback"
4801 BuiltinTypes
[IDLBuiltinType
.Types
.object],
4805 IDLUnresolvedIdentifier(
4806 BuiltinLocation("<auto-generated-identifier>"), "thisArg"
4808 BuiltinTypes
[IDLBuiltinType
.Types
.any
],
4814 # Iterable adds ES6 iterator style functions and traits
4815 # (keys/values/entries/@@iterator) to an interface.
4816 class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase
):
4817 def __init__(self
, location
, identifier
, keyType
, valueType
, scope
):
4818 IDLMaplikeOrSetlikeOrIterableBase
.__init
__(
4825 IDLInterfaceMember
.Tags
.Iterable
,
4827 self
.iteratorType
= None
4830 return "declared iterable with key '%s' and value '%s'" % (
4835 def expand(self
, members
):
4837 In order to take advantage of all of the method machinery in Codegen,
4838 we generate our functions as if they were part of the interface
4839 specification during parsing.
4841 # We only need to add entries/keys/values here if we're a pair iterator.
4842 # Value iterators just copy these from %ArrayPrototype% instead.
4843 if not self
.isPairIterator():
4852 affectsNothing
=True,
4854 isIteratorAlias
=True,
4862 affectsNothing
=True,
4871 affectsNothing
=True,
4875 # undefined forEach(callback(valueType, keyType), optional any thisArg)
4880 BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
4881 self
.getForEachArguments(),
4884 def isValueIterator(self
):
4885 return not self
.isPairIterator()
4887 def isPairIterator(self
):
4888 return self
.hasKeyType()
4891 class IDLAsyncIterable(IDLMaplikeOrSetlikeOrIterableBase
):
4892 def __init__(self
, location
, identifier
, keyType
, valueType
, argList
, scope
):
4894 if not arg
.optional
:
4896 "The arguments of the asynchronously iterable declaration on "
4897 "%s must all be optional arguments." % identifier
,
4901 IDLMaplikeOrSetlikeOrIterableBase
.__init
__(
4908 IDLInterfaceMember
.Tags
.AsyncIterable
,
4910 self
.iteratorType
= None
4911 self
.argList
= argList
4914 return "declared async iterable with key '%s' and value '%s'" % (
4919 def expand(self
, members
):
4921 In order to take advantage of all of the method machinery in Codegen,
4922 we generate our functions as if they were part of the interface
4923 specification during parsing.
4932 affectsNothing
=True,
4934 isIteratorAlias
=(not self
.isPairIterator()),
4937 # We only need to add entries/keys here if we're a pair iterator.
4938 if not self
.isPairIterator():
4941 # Methods can't share their IDLArguments, so we need to make copies here.
4942 def copyArgList(argList
):
4943 return map(copy
.copy
, argList
)
4951 copyArgList(self
.argList
),
4952 affectsNothing
=True,
4954 isIteratorAlias
=True,
4962 copyArgList(self
.argList
),
4963 affectsNothing
=True,
4967 def isValueIterator(self
):
4968 return not self
.isPairIterator()
4970 def isPairIterator(self
):
4971 return self
.hasKeyType()
4974 # MaplikeOrSetlike adds ES6 map-or-set-like traits to an interface.
4975 class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase
):
4977 self
, location
, identifier
, maplikeOrSetlikeType
, readonly
, keyType
, valueType
4979 IDLMaplikeOrSetlikeOrIterableBase
.__init
__(
4983 maplikeOrSetlikeType
,
4986 IDLInterfaceMember
.Tags
.MaplikeOrSetlike
,
4988 self
.readonly
= readonly
4989 self
.slotIndices
= None
4991 # When generating JSAPI access code, we need to know the backing object
4992 # type prefix to create the correct function. Generate here for reuse.
4993 if self
.isMaplike():
4995 elif self
.isSetlike():
4999 return "declared '%s' with key '%s'" % (
5000 self
.maplikeOrSetlikeOrIterableType
,
5004 def expand(self
, members
):
5006 In order to take advantage of all of the method machinery in Codegen,
5007 we generate our functions as if they were part of the interface
5008 specification during parsing.
5010 # Both maplike and setlike have a size attribute
5014 IDLUnresolvedIdentifier(
5015 BuiltinLocation("<auto-generated-identifier>"), "size"
5017 BuiltinTypes
[IDLBuiltinType
.Types
.unsigned_long
],
5019 maplikeOrSetlike
=self
,
5022 self
.reserved_ro_names
= ["size"]
5023 self
.disallowedMemberNames
.append("size")
5030 BuiltinTypes
[IDLBuiltinType
.Types
.object],
5031 affectsNothing
=True,
5032 isIteratorAlias
=self
.isMaplike(),
5039 BuiltinTypes
[IDLBuiltinType
.Types
.object],
5040 affectsNothing
=True,
5047 BuiltinTypes
[IDLBuiltinType
.Types
.object],
5048 affectsNothing
=True,
5049 isIteratorAlias
=self
.isSetlike(),
5052 # undefined forEach(callback(valueType, keyType), thisVal)
5057 BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
5058 self
.getForEachArguments(),
5064 IDLUnresolvedIdentifier(self
.location
, "key"),
5068 # boolean has(keyType key)
5073 BuiltinTypes
[IDLBuiltinType
.Types
.boolean
],
5078 if not self
.readonly
:
5081 "clear", members
, True, BuiltinTypes
[IDLBuiltinType
.Types
.undefined
], []
5083 # boolean delete(keyType key)
5088 BuiltinTypes
[IDLBuiltinType
.Types
.boolean
],
5092 if self
.isSetlike():
5093 if not self
.readonly
:
5094 # Add returns the set object it just added to.
5095 # object add(keyType key)
5101 BuiltinTypes
[IDLBuiltinType
.Types
.object],
5106 # If we get this far, we're a maplike declaration.
5108 # valueType get(keyType key)
5110 # Note that instead of the value type, we're using any here. The
5111 # validity checks should happen as things are inserted into the map,
5112 # and using any as the return type makes code generation much simpler.
5114 # TODO: Bug 1155340 may change this to use specific type to provide
5120 BuiltinTypes
[IDLBuiltinType
.Types
.any
],
5128 IDLUnresolvedIdentifier(self
.location
, "value"),
5132 if not self
.readonly
:
5137 BuiltinTypes
[IDLBuiltinType
.Types
.object],
5138 [getKeyArg(), getValueArg()],
5142 class IDLConst(IDLInterfaceMember
):
5143 def __init__(self
, location
, identifier
, type, value
):
5144 IDLInterfaceMember
.__init
__(
5145 self
, location
, identifier
, IDLInterfaceMember
.Tags
.Const
5148 assert isinstance(type, IDLType
)
5149 if type.isDictionary():
5151 "A constant cannot be of a dictionary type", [self
.location
]
5154 raise WebIDLError("A constant cannot be of a record type", [self
.location
])
5158 if identifier
.name
== "prototype":
5160 "The identifier of a constant must not be 'prototype'", [location
]
5164 return "'%s' const '%s'" % (self
.type, self
.identifier
)
5166 def finish(self
, scope
):
5167 IDLInterfaceMember
.finish(self
, scope
)
5169 if not self
.type.isComplete():
5170 type = self
.type.complete(scope
)
5171 if not type.isPrimitive() and not type.isString():
5172 locations
= [self
.type.location
, type.location
]
5174 locations
.append(type.inner
.location
)
5177 raise WebIDLError("Incorrect type for constant", locations
)
5180 # The value might not match the type
5181 coercedValue
= self
.value
.coerceToType(self
.type, self
.location
)
5184 self
.value
= coercedValue
5187 IDLInterfaceMember
.validate(self
)
5189 def handleExtendedAttribute(self
, attr
):
5190 identifier
= attr
.identifier()
5191 if identifier
== "Exposed":
5192 convertExposedAttrToGlobalNameSet(attr
, self
._exposureGlobalNames
)
5194 identifier
== "Pref"
5195 or identifier
== "ChromeOnly"
5196 or identifier
== "Func"
5197 or identifier
== "Trial"
5198 or identifier
== "SecureContext"
5199 or identifier
== "NonEnumerable"
5201 # Known attributes that we don't need to do anything with here
5205 "Unknown extended attribute %s on constant" % identifier
,
5208 IDLInterfaceMember
.handleExtendedAttribute(self
, attr
)
5210 def _getDependentObjects(self
):
5211 return set([self
.type, self
.value
])
5214 class IDLAttribute(IDLInterfaceMember
):
5224 maplikeOrSetlike
=None,
5225 extendedAttrDict
=None,
5227 IDLInterfaceMember
.__init
__(
5231 IDLInterfaceMember
.Tags
.Attr
,
5232 extendedAttrDict
=extendedAttrDict
,
5235 assert isinstance(type, IDLType
)
5237 self
.readonly
= readonly
5238 self
.inherit
= inherit
5239 self
._static
= static
5240 self
.legacyLenientThis
= False
5241 self
._legacyUnforgeable
= False
5242 self
.stringifier
= stringifier
5243 self
.slotIndices
= None
5244 assert maplikeOrSetlike
is None or isinstance(
5245 maplikeOrSetlike
, IDLMaplikeOrSetlike
5247 self
.maplikeOrSetlike
= maplikeOrSetlike
5248 self
.dependsOn
= "Everything"
5249 self
.affects
= "Everything"
5250 self
.bindingAliases
= []
5252 if static
and identifier
.name
== "prototype":
5254 "The identifier of a static attribute must not be 'prototype'",
5258 if readonly
and inherit
:
5260 "An attribute cannot be both 'readonly' and 'inherit'", [self
.location
]
5266 def forceStatic(self
):
5270 return "'%s' attribute '%s'" % (self
.type, self
.identifier
)
5272 def finish(self
, scope
):
5273 IDLInterfaceMember
.finish(self
, scope
)
5275 if not self
.type.isComplete():
5276 t
= self
.type.complete(scope
)
5278 assert not isinstance(t
, IDLUnresolvedType
)
5279 assert not isinstance(t
, IDLTypedefType
)
5280 assert not isinstance(t
.name
, IDLUnresolvedIdentifier
)
5283 if self
.readonly
and (
5284 self
.type.hasClamp()
5285 or self
.type.hasEnforceRange()
5286 or self
.type.hasAllowShared()
5287 or self
.type.legacyNullToEmptyString
5290 "A readonly attribute cannot be [Clamp] or [EnforceRange] or [AllowShared]",
5293 if self
.type.isDictionary() and not self
.getExtendedAttribute("Cached"):
5295 "An attribute cannot be of a dictionary type", [self
.location
]
5297 if self
.type.isSequence() and not self
.getExtendedAttribute("Cached"):
5299 "A non-cached attribute cannot be of a sequence " "type",
5302 if self
.type.isRecord() and not self
.getExtendedAttribute("Cached"):
5304 "A non-cached attribute cannot be of a record " "type", [self
.location
]
5306 if self
.type.isUnion():
5307 for f
in self
.type.unroll().flatMemberTypes
:
5308 if f
.isDictionary():
5310 "An attribute cannot be of a union "
5311 "type if one of its member types (or "
5312 "one of its member types's member "
5313 "types, and so on) is a dictionary "
5315 [self
.location
, f
.location
],
5319 "An attribute cannot be of a union "
5320 "type if one of its member types (or "
5321 "one of its member types's member "
5322 "types, and so on) is a sequence "
5324 [self
.location
, f
.location
],
5328 "An attribute cannot be of a union "
5329 "type if one of its member types (or "
5330 "one of its member types's member "
5331 "types, and so on) is a record "
5333 [self
.location
, f
.location
],
5335 if not self
.type.isInterface() and self
.getExtendedAttribute("PutForwards"):
5337 "An attribute with [PutForwards] must have an "
5338 "interface type as its type",
5342 if not self
.type.isInterface() and self
.getExtendedAttribute("SameObject"):
5344 "An attribute with [SameObject] must have an "
5345 "interface type as its type",
5349 if self
.type.isPromise() and not self
.readonly
:
5351 "Promise-returning attributes must be readonly", [self
.location
]
5354 if self
.type.isObservableArray():
5357 "A static attribute cannot have an ObservableArray type",
5360 if self
.getExtendedAttribute("Cached") or self
.getExtendedAttribute(
5364 "[Cached] and [StoreInSlot] must not be used "
5365 "on an attribute whose type is ObservableArray",
5370 def typeContainsChromeOnlyDictionaryMember(type):
5371 if type.nullable() or type.isSequence() or type.isRecord():
5372 return typeContainsChromeOnlyDictionaryMember(type.inner
)
5375 for memberType
in type.flatMemberTypes
:
5376 (contains
, location
) = typeContainsChromeOnlyDictionaryMember(
5380 return (True, location
)
5382 if type.isDictionary():
5383 dictionary
= type.inner
5385 (contains
, location
) = dictionaryContainsChromeOnlyMember(
5389 return (True, location
)
5390 dictionary
= dictionary
.parent
5392 return (False, None)
5394 def dictionaryContainsChromeOnlyMember(dictionary
):
5395 for member
in dictionary
.members
:
5396 if member
.getExtendedAttribute("ChromeOnly"):
5397 return (True, member
.location
)
5398 (contains
, location
) = typeContainsChromeOnlyDictionaryMember(
5402 return (True, location
)
5403 return (False, None)
5405 IDLInterfaceMember
.validate(self
)
5407 if self
.getExtendedAttribute("Cached") or self
.getExtendedAttribute(
5410 if not self
.affects
== "Nothing":
5412 "Cached attributes and attributes stored in "
5413 "slots must be Constant or Pure or "
5414 "Affects=Nothing, since the getter won't always "
5418 (contains
, location
) = typeContainsChromeOnlyDictionaryMember(self
.type)
5421 "[Cached] and [StoreInSlot] must not be used "
5422 "on an attribute whose type contains a "
5423 "[ChromeOnly] dictionary member",
5424 [self
.location
, location
],
5426 if self
.getExtendedAttribute("Frozen"):
5428 not self
.type.isSequence()
5429 and not self
.type.isDictionary()
5430 and not self
.type.isRecord()
5433 "[Frozen] is only allowed on "
5434 "sequence-valued, dictionary-valued, and "
5435 "record-valued attributes",
5438 if not self
.type.unroll().isExposedInAllOf(self
.exposureSet
):
5440 "Attribute returns a type that is not exposed "
5441 "everywhere where the attribute is exposed",
5444 if self
.getExtendedAttribute("CEReactions"):
5447 "[CEReactions] is not allowed on " "readonly attributes",
5451 def handleExtendedAttribute(self
, attr
):
5452 identifier
= attr
.identifier()
5454 identifier
== "SetterThrows"
5455 or identifier
== "SetterCanOOM"
5456 or identifier
== "SetterNeedsSubjectPrincipal"
5457 ) and self
.readonly
:
5459 "Readonly attributes must not be flagged as " "[%s]" % identifier
,
5462 elif identifier
== "BindingAlias":
5463 if not attr
.hasValue():
5465 "[BindingAlias] takes an identifier or string", [attr
.location
]
5467 self
._addBindingAlias
(attr
.value())
5470 identifier
== "Throws"
5471 or identifier
== "GetterThrows"
5472 or identifier
== "CanOOM"
5473 or identifier
== "GetterCanOOM"
5475 and self
.getExtendedAttribute("StoreInSlot")
5477 identifier
== "StoreInSlot"
5479 self
.getExtendedAttribute("Throws")
5480 or self
.getExtendedAttribute("GetterThrows")
5481 or self
.getExtendedAttribute("CanOOM")
5482 or self
.getExtendedAttribute("GetterCanOOM")
5485 raise WebIDLError("Throwing things can't be [StoreInSlot]", [attr
.location
])
5486 elif identifier
== "LegacyLenientThis":
5487 if not attr
.noArguments():
5489 "[LegacyLenientThis] must take no arguments", [attr
.location
]
5493 "[LegacyLenientThis] is only allowed on non-static " "attributes",
5494 [attr
.location
, self
.location
],
5496 if self
.getExtendedAttribute("CrossOriginReadable"):
5498 "[LegacyLenientThis] is not allowed in combination "
5499 "with [CrossOriginReadable]",
5500 [attr
.location
, self
.location
],
5502 if self
.getExtendedAttribute("CrossOriginWritable"):
5504 "[LegacyLenientThis] is not allowed in combination "
5505 "with [CrossOriginWritable]",
5506 [attr
.location
, self
.location
],
5508 self
.legacyLenientThis
= True
5509 elif identifier
== "LegacyUnforgeable":
5512 "[LegacyUnforgeable] is only allowed on non-static " "attributes",
5513 [attr
.location
, self
.location
],
5515 self
._legacyUnforgeable
= True
5516 elif identifier
== "SameObject" and not self
.readonly
:
5518 "[SameObject] only allowed on readonly attributes",
5519 [attr
.location
, self
.location
],
5521 elif identifier
== "Constant" and not self
.readonly
:
5523 "[Constant] only allowed on readonly attributes",
5524 [attr
.location
, self
.location
],
5526 elif identifier
== "PutForwards":
5527 if not self
.readonly
:
5529 "[PutForwards] is only allowed on readonly " "attributes",
5530 [attr
.location
, self
.location
],
5532 if self
.type.isPromise():
5534 "[PutForwards] is not allowed on " "Promise-typed attributes",
5535 [attr
.location
, self
.location
],
5539 "[PutForwards] is only allowed on non-static " "attributes",
5540 [attr
.location
, self
.location
],
5542 if self
.getExtendedAttribute("Replaceable") is not None:
5544 "[PutForwards] and [Replaceable] can't both "
5545 "appear on the same attribute",
5546 [attr
.location
, self
.location
],
5548 if not attr
.hasValue():
5550 "[PutForwards] takes an identifier", [attr
.location
, self
.location
]
5552 elif identifier
== "Replaceable":
5553 if not attr
.noArguments():
5555 "[Replaceable] must take no arguments", [attr
.location
]
5557 if not self
.readonly
:
5559 "[Replaceable] is only allowed on readonly " "attributes",
5560 [attr
.location
, self
.location
],
5562 if self
.type.isPromise():
5564 "[Replaceable] is not allowed on " "Promise-typed attributes",
5565 [attr
.location
, self
.location
],
5569 "[Replaceable] is only allowed on non-static " "attributes",
5570 [attr
.location
, self
.location
],
5572 if self
.getExtendedAttribute("PutForwards") is not None:
5574 "[PutForwards] and [Replaceable] can't both "
5575 "appear on the same attribute",
5576 [attr
.location
, self
.location
],
5578 elif identifier
== "LegacyLenientSetter":
5579 if not attr
.noArguments():
5581 "[LegacyLenientSetter] must take no arguments", [attr
.location
]
5583 if not self
.readonly
:
5585 "[LegacyLenientSetter] is only allowed on readonly " "attributes",
5586 [attr
.location
, self
.location
],
5588 if self
.type.isPromise():
5590 "[LegacyLenientSetter] is not allowed on "
5591 "Promise-typed attributes",
5592 [attr
.location
, self
.location
],
5596 "[LegacyLenientSetter] is only allowed on non-static " "attributes",
5597 [attr
.location
, self
.location
],
5599 if self
.getExtendedAttribute("PutForwards") is not None:
5601 "[LegacyLenientSetter] and [PutForwards] can't both "
5602 "appear on the same attribute",
5603 [attr
.location
, self
.location
],
5605 if self
.getExtendedAttribute("Replaceable") is not None:
5607 "[LegacyLenientSetter] and [Replaceable] can't both "
5608 "appear on the same attribute",
5609 [attr
.location
, self
.location
],
5611 elif identifier
== "LenientFloat":
5614 "[LenientFloat] used on a readonly attribute",
5615 [attr
.location
, self
.location
],
5617 if not self
.type.includesRestrictedFloat():
5619 "[LenientFloat] used on an attribute with a "
5620 "non-restricted-float type",
5621 [attr
.location
, self
.location
],
5623 elif identifier
== "StoreInSlot":
5624 if self
.getExtendedAttribute("Cached"):
5626 "[StoreInSlot] and [Cached] must not be "
5627 "specified on the same attribute",
5628 [attr
.location
, self
.location
],
5630 elif identifier
== "Cached":
5631 if self
.getExtendedAttribute("StoreInSlot"):
5633 "[Cached] and [StoreInSlot] must not be "
5634 "specified on the same attribute",
5635 [attr
.location
, self
.location
],
5637 elif identifier
== "CrossOriginReadable" or identifier
== "CrossOriginWritable":
5638 if not attr
.noArguments():
5640 "[%s] must take no arguments" % identifier
, [attr
.location
]
5644 "[%s] is only allowed on non-static " "attributes" % identifier
,
5645 [attr
.location
, self
.location
],
5647 if self
.getExtendedAttribute("LegacyLenientThis"):
5649 "[LegacyLenientThis] is not allowed in combination "
5650 "with [%s]" % identifier
,
5651 [attr
.location
, self
.location
],
5653 elif identifier
== "Exposed":
5654 convertExposedAttrToGlobalNameSet(attr
, self
._exposureGlobalNames
)
5655 elif identifier
== "Pure":
5656 if not attr
.noArguments():
5657 raise WebIDLError("[Pure] must take no arguments", [attr
.location
])
5658 self
._setDependsOn
("DOMState")
5659 self
._setAffects
("Nothing")
5660 elif identifier
== "Constant" or identifier
== "SameObject":
5661 if not attr
.noArguments():
5663 "[%s] must take no arguments" % identifier
, [attr
.location
]
5665 self
._setDependsOn
("Nothing")
5666 self
._setAffects
("Nothing")
5667 elif identifier
== "Affects":
5668 if not attr
.hasValue():
5669 raise WebIDLError("[Affects] takes an identifier", [attr
.location
])
5670 self
._setAffects
(attr
.value())
5671 elif identifier
== "DependsOn":
5672 if not attr
.hasValue():
5673 raise WebIDLError("[DependsOn] takes an identifier", [attr
.location
])
5675 attr
.value() != "Everything"
5676 and attr
.value() != "DOMState"
5677 and not self
.readonly
5680 "[DependsOn=%s] only allowed on "
5681 "readonly attributes" % attr
.value(),
5682 [attr
.location
, self
.location
],
5684 self
._setDependsOn
(attr
.value())
5685 elif identifier
== "UseCounter":
5686 if self
.stringifier
:
5688 "[UseCounter] must not be used on a " "stringifier attribute",
5689 [attr
.location
, self
.location
],
5691 elif identifier
== "Unscopable":
5692 if not attr
.noArguments():
5694 "[Unscopable] must take no arguments", [attr
.location
]
5698 "[Unscopable] is only allowed on non-static "
5699 "attributes and operations",
5700 [attr
.location
, self
.location
],
5702 elif identifier
== "CEReactions":
5703 if not attr
.noArguments():
5705 "[CEReactions] must take no arguments", [attr
.location
]
5708 identifier
== "Pref"
5709 or identifier
== "Deprecated"
5710 or identifier
== "SetterThrows"
5711 or identifier
== "Throws"
5712 or identifier
== "GetterThrows"
5713 or identifier
== "SetterCanOOM"
5714 or identifier
== "CanOOM"
5715 or identifier
== "GetterCanOOM"
5716 or identifier
== "ChromeOnly"
5717 or identifier
== "Func"
5718 or identifier
== "Trial"
5719 or identifier
== "SecureContext"
5720 or identifier
== "Frozen"
5721 or identifier
== "NewObject"
5722 or identifier
== "NeedsSubjectPrincipal"
5723 or identifier
== "SetterNeedsSubjectPrincipal"
5724 or identifier
== "GetterNeedsSubjectPrincipal"
5725 or identifier
== "NeedsCallerType"
5726 or identifier
== "BinaryName"
5727 or identifier
== "NonEnumerable"
5728 or identifier
== "BindingTemplate"
5730 # Known attributes that we don't need to do anything with here
5734 "Unknown extended attribute %s on attribute" % identifier
,
5737 IDLInterfaceMember
.handleExtendedAttribute(self
, attr
)
5739 def getExtendedAttributes(self
):
5740 return self
._extendedAttrDict
5742 def resolve(self
, parentScope
):
5743 assert isinstance(parentScope
, IDLScope
)
5744 self
.type.resolveType(parentScope
)
5745 IDLObjectWithIdentifier
.resolve(self
, parentScope
)
5747 def hasLegacyLenientThis(self
):
5748 return self
.legacyLenientThis
5750 def isMaplikeOrSetlikeAttr(self
):
5752 True if this attribute was generated from an interface with
5753 maplike/setlike (e.g. this is the size attribute for
5756 return self
.maplikeOrSetlike
is not None
5758 def isLegacyUnforgeable(self
):
5759 return self
._legacyUnforgeable
5761 def _getDependentObjects(self
):
5762 return set([self
.type])
5764 def expand(self
, members
):
5765 assert self
.stringifier
5767 not self
.type.isDOMString()
5768 and not self
.type.isUSVString()
5769 and not self
.type.isUTF8String()
5772 "The type of a stringifer attribute must be "
5773 "either DOMString, USVString or UTF8String",
5776 identifier
= IDLUnresolvedIdentifier(
5777 self
.location
, "__stringifier", allowDoubleUnderscore
=True
5782 returnType
=self
.type,
5785 underlyingAttr
=self
,
5787 allowedExtAttrs
= ["Throws", "NeedsSubjectPrincipal", "Pure"]
5788 # Safe to ignore these as they are only meaningful for attributes
5789 attributeOnlyExtAttrs
= [
5791 "CrossOriginWritable",
5794 for key
, value
in self
._extendedAttrDict
.items():
5795 if key
in allowedExtAttrs
:
5796 if value
is not True:
5798 "[%s] with a value is currently "
5799 "unsupported in stringifier attributes, "
5800 "please file a bug to add support" % key
,
5803 method
.addExtendedAttributes(
5804 [IDLExtendedAttribute(self
.location
, (key
,))]
5806 elif key
not in attributeOnlyExtAttrs
:
5808 "[%s] is currently unsupported in "
5809 "stringifier attributes, please file a bug "
5810 "to add support" % key
,
5813 members
.append(method
)
5816 class IDLArgument(IDLObjectWithIdentifier
):
5825 dictionaryMember
=False,
5826 allowTypeAttributes
=False,
5828 IDLObjectWithIdentifier
.__init
__(self
, location
, None, identifier
)
5830 assert isinstance(type, IDLType
)
5833 self
.optional
= optional
5834 self
.defaultValue
= defaultValue
5835 self
.variadic
= variadic
5836 self
.dictionaryMember
= dictionaryMember
5837 self
._isComplete
= False
5838 self
._allowTreatNonCallableAsNull
= False
5839 self
._extendedAttrDict
= {}
5840 self
.allowTypeAttributes
= allowTypeAttributes
5842 assert not variadic
or optional
5843 assert not variadic
or not defaultValue
5845 def addExtendedAttributes(self
, attrs
):
5846 for attribute
in attrs
:
5847 identifier
= attribute
.identifier()
5848 if self
.allowTypeAttributes
and (
5849 identifier
== "EnforceRange"
5850 or identifier
== "Clamp"
5851 or identifier
== "LegacyNullToEmptyString"
5852 or identifier
== "AllowShared"
5854 self
.type = self
.type.withExtendedAttributes([attribute
])
5855 elif identifier
== "TreatNonCallableAsNull":
5856 self
._allowTreatNonCallableAsNull
= True
5857 elif self
.dictionaryMember
and (
5858 identifier
== "ChromeOnly"
5859 or identifier
== "Func"
5860 or identifier
== "Trial"
5861 or identifier
== "Pref"
5863 if not self
.optional
:
5865 "[%s] must not be used on a required "
5866 "dictionary member" % identifier
,
5867 [attribute
.location
],
5869 elif self
.dictionaryMember
and identifier
== "BinaryType":
5870 if not len(attribute
.listValue()) == 1:
5872 "[%s] BinaryType must take one argument" % identifier
,
5873 [attribute
.location
],
5875 if not self
.defaultValue
:
5877 "[%s] BinaryType can't be used without default value"
5879 [attribute
.location
],
5883 "Unhandled extended attribute on %s"
5885 "a dictionary member"
5886 if self
.dictionaryMember
5889 [attribute
.location
],
5891 attrlist
= attribute
.listValue()
5892 self
._extendedAttrDict
[identifier
] = attrlist
if len(attrlist
) else True
5894 def getExtendedAttribute(self
, name
):
5895 return self
._extendedAttrDict
.get(name
, None)
5897 def isComplete(self
):
5898 return self
._isComplete
5900 def complete(self
, scope
):
5901 if self
._isComplete
:
5904 self
._isComplete
= True
5906 if not self
.type.isComplete():
5907 type = self
.type.complete(scope
)
5908 assert not isinstance(type, IDLUnresolvedType
)
5909 assert not isinstance(type, IDLTypedefType
)
5910 assert not isinstance(type.name
, IDLUnresolvedIdentifier
)
5913 if self
.type.isUndefined():
5915 "undefined must not be used as the type of an argument in any circumstance",
5919 if self
.type.isAny():
5920 assert self
.defaultValue
is None or isinstance(
5921 self
.defaultValue
, IDLNullValue
5923 # optional 'any' values always have a default value
5924 if self
.optional
and not self
.defaultValue
and not self
.variadic
:
5925 # Set the default value to undefined, for simplicity, so the
5926 # codegen doesn't have to special-case this.
5927 self
.defaultValue
= IDLUndefinedValue(self
.location
)
5929 if self
.dictionaryMember
and self
.type.legacyNullToEmptyString
:
5931 "Dictionary members cannot be [LegacyNullToEmptyString]",
5934 if self
.type.isObservableArray():
5936 "%s cannot have an ObservableArray type"
5937 % ("Dictionary members" if self
.dictionaryMember
else "Arguments"),
5940 # Now do the coercing thing; this needs to happen after the
5941 # above creation of a default value.
5942 if self
.defaultValue
:
5943 self
.defaultValue
= self
.defaultValue
.coerceToType(self
.type, self
.location
)
5944 assert self
.defaultValue
5946 def allowTreatNonCallableAsNull(self
):
5947 return self
._allowTreatNonCallableAsNull
5949 def _getDependentObjects(self
):
5950 deps
= set([self
.type])
5951 if self
.defaultValue
:
5952 deps
.add(self
.defaultValue
)
5955 def canHaveMissingValue(self
):
5956 return self
.optional
and not self
.defaultValue
5959 class IDLCallback(IDLObjectWithScope
):
5961 self
, location
, parentScope
, identifier
, returnType
, arguments
, isConstructor
5963 assert isinstance(returnType
, IDLType
)
5965 self
._returnType
= returnType
5967 self
._arguments
= list(arguments
)
5969 IDLObjectWithScope
.__init
__(self
, location
, parentScope
, identifier
)
5971 for returnType
, arguments
in self
.signatures():
5972 for argument
in arguments
:
5973 argument
.resolve(self
)
5975 self
._treatNonCallableAsNull
= False
5976 self
._treatNonObjectAsNull
= False
5977 self
._isRunScriptBoundary
= False
5978 self
._isConstructor
= isConstructor
5980 def isCallback(self
):
5983 def isConstructor(self
):
5984 return self
._isConstructor
5986 def signatures(self
):
5987 return [(self
._returnType
, self
._arguments
)]
5989 def finish(self
, scope
):
5990 if not self
._returnType
.isComplete():
5991 type = self
._returnType
.complete(scope
)
5993 assert not isinstance(type, IDLUnresolvedType
)
5994 assert not isinstance(type, IDLTypedefType
)
5995 assert not isinstance(type.name
, IDLUnresolvedIdentifier
)
5996 self
._returnType
= type
5998 for argument
in self
._arguments
:
5999 if argument
.type.isComplete():
6002 type = argument
.type.complete(scope
)
6004 assert not isinstance(type, IDLUnresolvedType
)
6005 assert not isinstance(type, IDLTypedefType
)
6006 assert not isinstance(type.name
, IDLUnresolvedIdentifier
)
6007 argument
.type = type
6010 for argument
in self
._arguments
:
6011 if argument
.type.isUndefined():
6013 "undefined must not be used as the type of an argument in any circumstance",
6017 def addExtendedAttributes(self
, attrs
):
6020 if attr
.identifier() == "TreatNonCallableAsNull":
6021 self
._treatNonCallableAsNull
= True
6022 elif attr
.identifier() == "LegacyTreatNonObjectAsNull":
6023 if self
._isConstructor
:
6025 "[LegacyTreatNonObjectAsNull] is not supported "
6029 self
._treatNonObjectAsNull
= True
6030 elif attr
.identifier() == "MOZ_CAN_RUN_SCRIPT_BOUNDARY":
6031 if self
._isConstructor
:
6033 "[MOZ_CAN_RUN_SCRIPT_BOUNDARY] is not "
6034 "permitted on constructors",
6037 self
._isRunScriptBoundary
= True
6039 unhandledAttrs
.append(attr
)
6040 if self
._treatNonCallableAsNull
and self
._treatNonObjectAsNull
:
6042 "Cannot specify both [TreatNonCallableAsNull] "
6043 "and [LegacyTreatNonObjectAsNull]",
6046 if len(unhandledAttrs
) != 0:
6047 IDLType
.addExtendedAttributes(self
, unhandledAttrs
)
6049 def _getDependentObjects(self
):
6050 return set([self
._returnType
] + self
._arguments
)
6052 def isRunScriptBoundary(self
):
6053 return self
._isRunScriptBoundary
6056 class IDLCallbackType(IDLType
):
6057 def __init__(self
, location
, callback
):
6058 IDLType
.__init
__(self
, location
, callback
.identifier
.name
)
6059 self
.callback
= callback
6061 def isCallback(self
):
6065 return IDLType
.Tags
.callback
6067 def isDistinguishableFrom(self
, other
):
6068 if other
.isPromise():
6071 # Just forward to the union; it'll deal
6072 return other
.isDistinguishableFrom(self
)
6073 # Callbacks without `LegacyTreatNonObjectAsNull` are distinguishable from Dictionary likes
6074 if other
.isDictionaryLike():
6075 return not self
.callback
._treatNonObjectAsNull
6078 or other
.isPrimitive()
6081 or other
.isNonCallbackInterface()
6082 or other
.isSequence()
6085 def _getDependentObjects(self
):
6086 return self
.callback
._getDependentObjects
()
6089 class IDLMethodOverload
:
6091 A class that represents a single overload of a WebIDL method. This is not
6092 quite the same as an element of the "effective overload set" in the spec,
6093 because separate IDLMethodOverloads are not created based on arguments being
6094 optional. Rather, when multiple methods have the same name, there is an
6095 IDLMethodOverload for each one, all hanging off an IDLMethod representing
6096 the full set of overloads.
6099 def __init__(self
, returnType
, arguments
, location
):
6100 self
.returnType
= returnType
6101 # Clone the list of arguments, just in case
6102 self
.arguments
= list(arguments
)
6103 self
.location
= location
6105 def _getDependentObjects(self
):
6106 deps
= set(self
.arguments
)
6107 deps
.add(self
.returnType
)
6110 def includesRestrictedFloatArgument(self
):
6111 return any(arg
.type.includesRestrictedFloat() for arg
in self
.arguments
)
6114 class IDLMethod(IDLInterfaceMember
, IDLScope
):
6116 "Getter", "Setter", "Deleter", "LegacyCaller", base
=IDLInterfaceMember
.Special
6119 NamedOrIndexed
= enum("Neither", "Named", "Indexed")
6131 specialType
=NamedOrIndexed
.Neither
,
6134 maplikeOrSetlikeOrIterable
=None,
6135 underlyingAttr
=None,
6137 # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up.
6138 IDLInterfaceMember
.__init
__(
6139 self
, location
, identifier
, IDLInterfaceMember
.Tags
.Method
6142 self
._hasOverloads
= False
6144 assert isinstance(returnType
, IDLType
)
6146 # self._overloads is a list of IDLMethodOverloads
6147 self
._overloads
= [IDLMethodOverload(returnType
, arguments
, location
)]
6149 assert isinstance(static
, bool)
6150 self
._static
= static
6151 assert isinstance(getter
, bool)
6152 self
._getter
= getter
6153 assert isinstance(setter
, bool)
6154 self
._setter
= setter
6155 assert isinstance(deleter
, bool)
6156 self
._deleter
= deleter
6157 assert isinstance(legacycaller
, bool)
6158 self
._legacycaller
= legacycaller
6159 assert isinstance(stringifier
, bool)
6160 self
._stringifier
= stringifier
6161 assert maplikeOrSetlikeOrIterable
is None or isinstance(
6162 maplikeOrSetlikeOrIterable
, IDLMaplikeOrSetlikeOrIterableBase
6164 self
.maplikeOrSetlikeOrIterable
= maplikeOrSetlikeOrIterable
6165 self
._htmlConstructor
= False
6166 self
.underlyingAttr
= underlyingAttr
6167 self
._specialType
= specialType
6168 self
._legacyUnforgeable
= False
6169 self
.dependsOn
= "Everything"
6170 self
.affects
= "Everything"
6173 if static
and identifier
.name
== "prototype":
6175 "The identifier of a static operation must not be 'prototype'",
6179 self
.assertSignatureConstraints()
6182 return "Method '%s'" % self
.identifier
6184 def assertSignatureConstraints(self
):
6185 if self
._getter
or self
._deleter
:
6186 assert len(self
._overloads
) == 1
6187 overload
= self
._overloads
[0]
6188 arguments
= overload
.arguments
6189 assert len(arguments
) == 1
6191 arguments
[0].type == BuiltinTypes
[IDLBuiltinType
.Types
.domstring
]
6192 or arguments
[0].type == BuiltinTypes
[IDLBuiltinType
.Types
.unsigned_long
]
6194 assert not arguments
[0].optional
and not arguments
[0].variadic
6195 assert not self
._getter
or not overload
.returnType
.isUndefined()
6198 assert len(self
._overloads
) == 1
6199 arguments
= self
._overloads
[0].arguments
6200 assert len(arguments
) == 2
6202 arguments
[0].type == BuiltinTypes
[IDLBuiltinType
.Types
.domstring
]
6203 or arguments
[0].type == BuiltinTypes
[IDLBuiltinType
.Types
.unsigned_long
]
6205 assert not arguments
[0].optional
and not arguments
[0].variadic
6206 assert not arguments
[1].optional
and not arguments
[1].variadic
6208 if self
._stringifier
:
6209 assert len(self
._overloads
) == 1
6210 overload
= self
._overloads
[0]
6211 assert len(overload
.arguments
) == 0
6212 if not self
.underlyingAttr
:
6214 overload
.returnType
== BuiltinTypes
[IDLBuiltinType
.Types
.domstring
]
6220 def forceStatic(self
):
6229 def isDeleter(self
):
6230 return self
._deleter
6234 self
._specialType
== IDLMethod
.NamedOrIndexed
.Named
6235 or self
._specialType
== IDLMethod
.NamedOrIndexed
.Indexed
6237 return self
._specialType
== IDLMethod
.NamedOrIndexed
.Named
6239 def isIndexed(self
):
6241 self
._specialType
== IDLMethod
.NamedOrIndexed
.Named
6242 or self
._specialType
== IDLMethod
.NamedOrIndexed
.Indexed
6244 return self
._specialType
== IDLMethod
.NamedOrIndexed
.Indexed
6246 def isLegacycaller(self
):
6247 return self
._legacycaller
6249 def isStringifier(self
):
6250 return self
._stringifier
6253 return self
.identifier
.name
== "toJSON"
6255 def isDefaultToJSON(self
):
6256 return self
.isToJSON() and self
.getExtendedAttribute("Default")
6258 def isMaplikeOrSetlikeOrIterableMethod(self
):
6260 True if this method was generated as part of a
6261 maplike/setlike/etc interface (e.g. has/get methods)
6263 return self
.maplikeOrSetlikeOrIterable
is not None
6265 def isSpecial(self
):
6270 or self
.isLegacycaller()
6271 or self
.isStringifier()
6274 def isHTMLConstructor(self
):
6275 return self
._htmlConstructor
6277 def hasOverloads(self
):
6278 return self
._hasOverloads
6280 def isIdentifierLess(self
):
6282 True if the method name started with __, and if the method is not a
6283 maplike/setlike method. Interfaces with maplike/setlike will generate
6284 methods starting with __ for chrome only backing object access in JS
6285 implemented interfaces, so while these functions use what is considered
6286 an non-identifier name, they actually DO have an identifier.
6289 self
.identifier
.name
[:2] == "__"
6290 and not self
.isMaplikeOrSetlikeOrIterableMethod()
6293 def resolve(self
, parentScope
):
6294 assert isinstance(parentScope
, IDLScope
)
6295 IDLObjectWithIdentifier
.resolve(self
, parentScope
)
6296 IDLScope
.__init
__(self
, self
.location
, parentScope
, self
.identifier
)
6297 for returnType
, arguments
in self
.signatures():
6298 for argument
in arguments
:
6299 argument
.resolve(self
)
6301 def addOverload(self
, method
):
6302 assert len(method
._overloads
) == 1
6304 if self
._extendedAttrDict
!= method
._extendedAttrDict
:
6305 extendedAttrDiff
= set(self
._extendedAttrDict
.keys()) ^
set(
6306 method
._extendedAttrDict
.keys()
6309 if extendedAttrDiff
== {"LenientFloat"}:
6310 if "LenientFloat" not in self
._extendedAttrDict
:
6311 for overload
in self
._overloads
:
6312 if overload
.includesRestrictedFloatArgument():
6314 "Restricted float behavior differs on different "
6315 "overloads of %s" % method
.identifier
,
6316 [overload
.location
, method
.location
],
6318 self
._extendedAttrDict
["LenientFloat"] = method
._extendedAttrDict
[
6321 elif method
._overloads
[0].includesRestrictedFloatArgument():
6323 "Restricted float behavior differs on different "
6324 "overloads of %s" % method
.identifier
,
6325 [self
.location
, method
.location
],
6329 "Extended attributes differ on different "
6330 "overloads of %s" % method
.identifier
,
6331 [self
.location
, method
.location
],
6334 self
._overloads
.extend(method
._overloads
)
6336 self
._hasOverloads
= True
6338 if self
.isStatic() != method
.isStatic():
6340 "Overloaded identifier %s appears with different values of the 'static' attribute"
6341 % method
.identifier
,
6345 if self
.isLegacycaller() != method
.isLegacycaller():
6348 "Overloaded identifier %s appears with different "
6349 "values of the 'legacycaller' attribute" % method
.identifier
6354 # Can't overload special things!
6357 or method
.isGetter()
6359 or method
.isSetter()
6361 or method
.isDeleter()
6362 or self
.isStringifier()
6363 or method
.isStringifier()
6366 ("Can't overload a special operation"),
6367 [self
.location
, method
.location
],
6369 if self
.isHTMLConstructor() or method
.isHTMLConstructor():
6372 "An interface must contain only a single operation annotated with HTMLConstructor, and no others"
6374 [self
.location
, method
.location
],
6379 def signatures(self
):
6381 (overload
.returnType
, overload
.arguments
) for overload
in self
._overloads
6384 def finish(self
, scope
):
6385 IDLInterfaceMember
.finish(self
, scope
)
6387 for overload
in self
._overloads
:
6388 returnType
= overload
.returnType
6389 if not returnType
.isComplete():
6390 returnType
= returnType
.complete(scope
)
6391 assert not isinstance(returnType
, IDLUnresolvedType
)
6392 assert not isinstance(returnType
, IDLTypedefType
)
6393 assert not isinstance(returnType
.name
, IDLUnresolvedIdentifier
)
6394 overload
.returnType
= returnType
6396 for argument
in overload
.arguments
:
6397 if not argument
.isComplete():
6398 argument
.complete(scope
)
6399 assert argument
.type.isComplete()
6401 # Now compute various information that will be used by the
6402 # WebIDL overload resolution algorithm.
6403 self
.maxArgCount
= max(len(s
[1]) for s
in self
.signatures())
6404 self
.allowedArgCounts
= [
6406 for i
in range(self
.maxArgCount
+ 1)
6407 if len(self
.signaturesForArgCount(i
)) != 0
6411 IDLInterfaceMember
.validate(self
)
6413 # Make sure our overloads are properly distinguishable and don't have
6414 # different argument types before the distinguishing args.
6415 for argCount
in self
.allowedArgCounts
:
6416 possibleOverloads
= self
.overloadsForArgCount(argCount
)
6417 if len(possibleOverloads
) == 1:
6419 distinguishingIndex
= self
.distinguishingIndexForArgCount(argCount
)
6420 for idx
in range(distinguishingIndex
):
6421 firstSigType
= possibleOverloads
[0].arguments
[idx
].type
6422 for overload
in possibleOverloads
[1:]:
6423 if overload
.arguments
[idx
].type != firstSigType
:
6425 "Signatures for method '%s' with %d arguments have "
6426 "different types of arguments at index %d, which "
6427 "is before distinguishing index %d"
6429 self
.identifier
.name
,
6432 distinguishingIndex
,
6434 [self
.location
, overload
.location
],
6437 overloadWithPromiseReturnType
= None
6438 overloadWithoutPromiseReturnType
= None
6439 for overload
in self
._overloads
:
6440 returnType
= overload
.returnType
6441 if not returnType
.unroll().isExposedInAllOf(self
.exposureSet
):
6443 "Overload returns a type that is not exposed "
6444 "everywhere where the method is exposed",
6445 [overload
.location
],
6448 variadicArgument
= None
6450 arguments
= overload
.arguments
6451 for idx
, argument
in enumerate(arguments
):
6452 assert argument
.type.isComplete()
6455 argument
.type.isDictionary()
6456 and argument
.type.unroll().inner
.canBeEmpty()
6458 argument
.type.isUnion()
6459 and argument
.type.unroll().hasPossiblyEmptyDictionaryType()
6461 # Optional dictionaries and unions containing optional
6462 # dictionaries at the end of the list or followed by
6463 # optional arguments must be optional.
6464 if not argument
.optional
and all(
6465 arg
.optional
for arg
in arguments
[idx
+ 1 :]
6468 "Dictionary argument without any "
6469 "required fields or union argument "
6470 "containing such dictionary not "
6471 "followed by a required argument "
6473 [argument
.location
],
6476 if not argument
.defaultValue
and all(
6477 arg
.optional
for arg
in arguments
[idx
+ 1 :]
6480 "Dictionary argument without any "
6481 "required fields or union argument "
6482 "containing such dictionary not "
6483 "followed by a required argument "
6484 "must have a default value",
6485 [argument
.location
],
6488 # An argument cannot be a nullable dictionary or a
6489 # nullable union containing a dictionary.
6490 if argument
.type.nullable() and (
6491 argument
.type.isDictionary()
6493 argument
.type.isUnion()
6494 and argument
.type.unroll().hasDictionaryType()
6498 "An argument cannot be a nullable "
6499 "dictionary or nullable union "
6500 "containing a dictionary",
6501 [argument
.location
],
6504 # Only the last argument can be variadic
6505 if variadicArgument
:
6507 "Variadic argument is not last argument",
6508 [variadicArgument
.location
],
6510 if argument
.variadic
:
6511 variadicArgument
= argument
6513 if returnType
.isPromise():
6514 overloadWithPromiseReturnType
= overload
6516 overloadWithoutPromiseReturnType
= overload
6518 # Make sure either all our overloads return Promises or none do
6519 if overloadWithPromiseReturnType
and overloadWithoutPromiseReturnType
:
6521 "We have overloads with both Promise and " "non-Promise return types",
6523 overloadWithPromiseReturnType
.location
,
6524 overloadWithoutPromiseReturnType
.location
,
6528 if overloadWithPromiseReturnType
and self
._legacycaller
:
6530 "May not have a Promise return type for a " "legacycaller.",
6531 [overloadWithPromiseReturnType
.location
],
6534 if self
.getExtendedAttribute("StaticClassOverride") and not (
6535 self
.identifier
.scope
.isJSImplemented() and self
.isStatic()
6538 "StaticClassOverride can be applied to static"
6539 " methods on JS-implemented classes only.",
6543 # Ensure that toJSON methods satisfy the spec constraints on them.
6544 if self
.identifier
.name
== "toJSON":
6545 if len(self
.signatures()) != 1:
6547 "toJSON method has multiple overloads",
6548 [self
._overloads
[0].location
, self
._overloads
[1].location
],
6550 if len(self
.signatures()[0][1]) != 0:
6551 raise WebIDLError("toJSON method has arguments", [self
.location
])
6552 if not self
.signatures()[0][0].isJSONType():
6554 "toJSON method has non-JSON return type", [self
.location
]
6557 def overloadsForArgCount(self
, argc
):
6560 for overload
in self
._overloads
6561 if len(overload
.arguments
) == argc
6563 len(overload
.arguments
) > argc
6564 and all(arg
.optional
for arg
in overload
.arguments
[argc
:])
6567 len(overload
.arguments
) < argc
6568 and len(overload
.arguments
) > 0
6569 and overload
.arguments
[-1].variadic
6573 def signaturesForArgCount(self
, argc
):
6575 (overload
.returnType
, overload
.arguments
)
6576 for overload
in self
.overloadsForArgCount(argc
)
6579 def locationsForArgCount(self
, argc
):
6580 return [overload
.location
for overload
in self
.overloadsForArgCount(argc
)]
6582 def distinguishingIndexForArgCount(self
, argc
):
6583 def isValidDistinguishingIndex(idx
, signatures
):
6584 for firstSigIndex
, (firstRetval
, firstArgs
) in enumerate(signatures
[:-1]):
6585 for secondRetval
, secondArgs
in signatures
[firstSigIndex
+ 1 :]:
6586 if idx
< len(firstArgs
):
6587 firstType
= firstArgs
[idx
].type
6589 assert firstArgs
[-1].variadic
6590 firstType
= firstArgs
[-1].type
6591 if idx
< len(secondArgs
):
6592 secondType
= secondArgs
[idx
].type
6594 assert secondArgs
[-1].variadic
6595 secondType
= secondArgs
[-1].type
6596 if not firstType
.isDistinguishableFrom(secondType
):
6600 signatures
= self
.signaturesForArgCount(argc
)
6601 for idx
in range(argc
):
6602 if isValidDistinguishingIndex(idx
, signatures
):
6604 # No valid distinguishing index. Time to throw
6605 locations
= self
.locationsForArgCount(argc
)
6607 "Signatures with %d arguments for method '%s' are not "
6608 "distinguishable" % (argc
, self
.identifier
.name
),
6612 def handleExtendedAttribute(self
, attr
):
6613 identifier
= attr
.identifier()
6615 identifier
== "GetterThrows"
6616 or identifier
== "SetterThrows"
6617 or identifier
== "GetterCanOOM"
6618 or identifier
== "SetterCanOOM"
6619 or identifier
== "SetterNeedsSubjectPrincipal"
6620 or identifier
== "GetterNeedsSubjectPrincipal"
6623 "Methods must not be flagged as " "[%s]" % identifier
,
6624 [attr
.location
, self
.location
],
6626 elif identifier
== "LegacyUnforgeable":
6629 "[LegacyUnforgeable] is only allowed on non-static " "methods",
6630 [attr
.location
, self
.location
],
6632 self
._legacyUnforgeable
= True
6633 elif identifier
== "SameObject":
6635 "Methods must not be flagged as [SameObject]",
6636 [attr
.location
, self
.location
],
6638 elif identifier
== "Constant":
6640 "Methods must not be flagged as [Constant]",
6641 [attr
.location
, self
.location
],
6643 elif identifier
== "PutForwards":
6645 "Only attributes support [PutForwards]", [attr
.location
, self
.location
]
6647 elif identifier
== "LegacyLenientSetter":
6649 "Only attributes support [LegacyLenientSetter]",
6650 [attr
.location
, self
.location
],
6652 elif identifier
== "LenientFloat":
6653 # This is called before we've done overload resolution
6654 overloads
= self
._overloads
6655 assert len(overloads
) == 1
6656 if not overloads
[0].returnType
.isUndefined():
6658 "[LenientFloat] used on a non-undefined method",
6659 [attr
.location
, self
.location
],
6661 if not overloads
[0].includesRestrictedFloatArgument():
6663 "[LenientFloat] used on an operation with no "
6664 "restricted float type arguments",
6665 [attr
.location
, self
.location
],
6667 elif identifier
== "Exposed":
6668 convertExposedAttrToGlobalNameSet(attr
, self
._exposureGlobalNames
)
6670 identifier
== "CrossOriginCallable"
6671 or identifier
== "WebGLHandlesContextLoss"
6673 # Known no-argument attributes.
6674 if not attr
.noArguments():
6676 "[%s] must take no arguments" % identifier
, [attr
.location
]
6678 if identifier
== "CrossOriginCallable" and self
.isStatic():
6680 "[CrossOriginCallable] is only allowed on non-static " "attributes",
6681 [attr
.location
, self
.location
],
6683 elif identifier
== "Pure":
6684 if not attr
.noArguments():
6685 raise WebIDLError("[Pure] must take no arguments", [attr
.location
])
6686 self
._setDependsOn
("DOMState")
6687 self
._setAffects
("Nothing")
6688 elif identifier
== "Affects":
6689 if not attr
.hasValue():
6690 raise WebIDLError("[Affects] takes an identifier", [attr
.location
])
6691 self
._setAffects
(attr
.value())
6692 elif identifier
== "DependsOn":
6693 if not attr
.hasValue():
6694 raise WebIDLError("[DependsOn] takes an identifier", [attr
.location
])
6695 self
._setDependsOn
(attr
.value())
6696 elif identifier
== "Alias":
6697 if not attr
.hasValue():
6699 "[Alias] takes an identifier or string", [attr
.location
]
6701 self
._addAlias
(attr
.value())
6702 elif identifier
== "UseCounter":
6703 if self
.isSpecial():
6705 "[UseCounter] must not be used on a special " "operation",
6706 [attr
.location
, self
.location
],
6708 elif identifier
== "Unscopable":
6709 if not attr
.noArguments():
6711 "[Unscopable] must take no arguments", [attr
.location
]
6715 "[Unscopable] is only allowed on non-static "
6716 "attributes and operations",
6717 [attr
.location
, self
.location
],
6719 elif identifier
== "CEReactions":
6720 if not attr
.noArguments():
6722 "[CEReactions] must take no arguments", [attr
.location
]
6725 if self
.isSpecial() and not self
.isSetter() and not self
.isDeleter():
6727 "[CEReactions] is only allowed on operation, "
6728 "attribute, setter, and deleter",
6729 [attr
.location
, self
.location
],
6731 elif identifier
== "Default":
6732 if not attr
.noArguments():
6733 raise WebIDLError("[Default] must take no arguments", [attr
.location
])
6735 if not self
.isToJSON():
6737 "[Default] is only allowed on toJSON operations",
6738 [attr
.location
, self
.location
],
6741 if self
.signatures()[0][0] != BuiltinTypes
[IDLBuiltinType
.Types
.object]:
6743 "The return type of the default toJSON "
6744 "operation must be 'object'",
6745 [attr
.location
, self
.location
],
6748 identifier
== "Throws"
6749 or identifier
== "CanOOM"
6750 or identifier
== "NewObject"
6751 or identifier
== "ChromeOnly"
6752 or identifier
== "Pref"
6753 or identifier
== "Deprecated"
6754 or identifier
== "Func"
6755 or identifier
== "Trial"
6756 or identifier
== "SecureContext"
6757 or identifier
== "BinaryName"
6758 or identifier
== "NeedsSubjectPrincipal"
6759 or identifier
== "NeedsCallerType"
6760 or identifier
== "StaticClassOverride"
6761 or identifier
== "NonEnumerable"
6762 or identifier
== "Unexposed"
6763 or identifier
== "WebExtensionStub"
6765 # Known attributes that we don't need to do anything with here
6769 "Unknown extended attribute %s on method" % identifier
, [attr
.location
]
6771 IDLInterfaceMember
.handleExtendedAttribute(self
, attr
)
6773 def returnsPromise(self
):
6774 return self
._overloads
[0].returnType
.isPromise()
6776 def isLegacyUnforgeable(self
):
6777 return self
._legacyUnforgeable
6779 def _getDependentObjects(self
):
6781 for overload
in self
._overloads
:
6782 deps
.update(overload
._getDependentObjects
())
6786 class IDLConstructor(IDLMethod
):
6787 def __init__(self
, location
, args
, name
):
6788 # We can't actually init our IDLMethod yet, because we do not know the
6789 # return type yet. Just save the info we have for now and we will init
6791 self
._initLocation
= location
6792 self
._initArgs
= args
6793 self
._initName
= name
6794 self
._inited
= False
6795 self
._initExtendedAttrs
= []
6797 def addExtendedAttributes(self
, attrs
):
6799 return IDLMethod
.addExtendedAttributes(self
, attrs
)
6800 self
._initExtendedAttrs
.extend(attrs
)
6802 def handleExtendedAttribute(self
, attr
):
6803 identifier
= attr
.identifier()
6805 identifier
== "BinaryName"
6806 or identifier
== "ChromeOnly"
6807 or identifier
== "NewObject"
6808 or identifier
== "SecureContext"
6809 or identifier
== "Throws"
6810 or identifier
== "Func"
6811 or identifier
== "Trial"
6812 or identifier
== "Pref"
6813 or identifier
== "UseCounter"
6815 IDLMethod
.handleExtendedAttribute(self
, attr
)
6816 elif identifier
== "HTMLConstructor":
6817 if not attr
.noArguments():
6819 "[HTMLConstructor] must take no arguments", [attr
.location
]
6821 # We shouldn't end up here for legacy factory functions.
6822 assert self
.identifier
.name
== "constructor"
6824 if any(len(sig
[1]) != 0 for sig
in self
.signatures()):
6826 "[HTMLConstructor] must not be applied to a "
6827 "constructor operation that has arguments.",
6830 self
._htmlConstructor
= True
6833 "Unknown extended attribute %s on method" % identifier
, [attr
.location
]
6836 def reallyInit(self
, parentInterface
):
6837 name
= self
._initName
6838 location
= self
._initLocation
6839 identifier
= IDLUnresolvedIdentifier(location
, name
, allowForbidden
=True)
6840 retType
= IDLWrapperType(parentInterface
.location
, parentInterface
)
6842 self
, location
, identifier
, retType
, self
._initArgs
, static
=True
6845 # Propagate through whatever extended attributes we already had
6846 self
.addExtendedAttributes(self
._initExtendedAttrs
)
6847 self
._initExtendedAttrs
= []
6848 # Constructors are always NewObject. Whether they throw or not is
6849 # indicated by [Throws] annotations in the usual way.
6850 self
.addExtendedAttributes(
6851 [IDLExtendedAttribute(self
.location
, ("NewObject",))]
6855 class IDLIncludesStatement(IDLObject
):
6856 def __init__(self
, location
, interface
, mixin
):
6857 IDLObject
.__init
__(self
, location
)
6858 self
.interface
= interface
6860 self
._finished
= False
6862 def finish(self
, scope
):
6865 self
._finished
= True
6866 assert isinstance(self
.interface
, IDLIdentifierPlaceholder
)
6867 assert isinstance(self
.mixin
, IDLIdentifierPlaceholder
)
6868 interface
= self
.interface
.finish(scope
)
6869 mixin
= self
.mixin
.finish(scope
)
6870 # NOTE: we depend on not setting self.interface and
6871 # self.mixin here to keep track of the original
6873 if not isinstance(interface
, IDLInterface
):
6875 "Left-hand side of 'includes' is not an " "interface",
6876 [self
.interface
.location
, interface
.location
],
6878 if interface
.isCallback():
6880 "Left-hand side of 'includes' is a callback " "interface",
6881 [self
.interface
.location
, interface
.location
],
6883 if not isinstance(mixin
, IDLInterfaceMixin
):
6885 "Right-hand side of 'includes' is not an " "interface mixin",
6886 [self
.mixin
.location
, mixin
.location
],
6889 mixin
.actualExposureGlobalNames
.update(interface
._exposureGlobalNames
)
6891 interface
.addIncludedMixin(mixin
)
6892 self
.interface
= interface
6898 def addExtendedAttributes(self
, attrs
):
6901 "There are no extended attributes that are "
6902 "allowed on includes statements",
6903 [attrs
[0].location
, self
.location
],
6907 class IDLExtendedAttribute(IDLObject
):
6909 A class to represent IDL extended attributes so we can give them locations
6912 def __init__(self
, location
, tuple):
6913 IDLObject
.__init
__(self
, location
)
6916 def identifier(self
):
6917 return self
._tuple
[0]
6919 def noArguments(self
):
6920 return len(self
._tuple
) == 1
6923 return len(self
._tuple
) >= 2 and isinstance(self
._tuple
[1], str)
6926 assert self
.hasValue()
6927 return self
._tuple
[1]
6931 len(self
._tuple
) == 2
6932 and isinstance(self
._tuple
[1], list)
6933 or len(self
._tuple
) == 3
6937 assert self
.hasArgs()
6938 # Our args are our last element
6939 return self
._tuple
[-1]
6941 def listValue(self
):
6943 Backdoor for storing random data in _extendedAttrDict
6945 return list(self
._tuple
)[1:]
6951 class Tokenizer(object):
6952 tokens
= ["INTEGER", "FLOATLITERAL", "IDENTIFIER", "STRING", "WHITESPACE", "OTHER"]
6954 def t_FLOATLITERAL(self
, t
):
6955 r
"(-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+|Infinity))|NaN"
6956 t
.value
= float(t
.value
)
6959 def t_INTEGER(self
, t
):
6960 r
"-?(0([0-7]+|[Xx][0-9A-Fa-f]+)?|[1-9][0-9]*)"
6962 # Can't use int(), because that doesn't handle octal properly.
6963 t
.value
= parseInt(t
.value
)
6966 "Invalid integer literal",
6970 lineno
=self
.lexer
.lineno
,
6971 lexpos
=self
.lexer
.lexpos
,
6972 filename
=self
._filename
,
6978 def t_IDENTIFIER(self
, t
):
6979 r
"[_-]?[A-Za-z][0-9A-Z_a-z-]*"
6980 t
.type = self
.keywords
.get(t
.value
, "IDENTIFIER")
6983 def t_STRING(self
, t
):
6985 t
.value
= t
.value
[1:-1]
6988 def t_WHITESPACE(self
, t
):
6989 r
"[\t\n\r ]+|[\t\n\r ]*((//[^\n]*|/\*.*?\*/)[\t\n\r ]*)+"
6992 def t_ELLIPSIS(self
, t
):
6994 t
.type = self
.keywords
.get(t
.value
)
6997 def t_OTHER(self
, t
):
6998 r
"[^\t\n\r 0-9A-Z_a-z]"
6999 t
.type = self
.keywords
.get(t
.value
, "OTHER")
7003 "interface": "INTERFACE",
7004 "partial": "PARTIAL",
7006 "dictionary": "DICTIONARY",
7007 "exception": "EXCEPTION",
7009 "callback": "CALLBACK",
7010 "typedef": "TYPEDEF",
7011 "includes": "INCLUDES",
7016 "serializer": "SERIALIZER",
7017 "stringifier": "STRINGIFIER",
7018 "unrestricted": "UNRESTRICTED",
7019 "attribute": "ATTRIBUTE",
7020 "readonly": "READONLY",
7021 "inherit": "INHERIT",
7025 "deleter": "DELETER",
7026 "legacycaller": "LEGACYCALLER",
7027 "optional": "OPTIONAL",
7030 "DOMString": "DOMSTRING",
7031 "ByteString": "BYTESTRING",
7032 "USVString": "USVSTRING",
7033 "JSString": "JSSTRING",
7034 "UTF8String": "UTF8STRING",
7036 "boolean": "BOOLEAN",
7042 "ObservableArray": "OBSERVABLEARRAY",
7044 "Promise": "PROMISE",
7045 "required": "REQUIRED",
7046 "sequence": "SEQUENCE",
7049 "unsigned": "UNSIGNED",
7050 "undefined": "UNDEFINED",
7059 "?": "QUESTIONMARK",
7065 "ArrayBuffer": "ARRAYBUFFER",
7067 "maplike": "MAPLIKE",
7068 "setlike": "SETLIKE",
7069 "iterable": "ITERABLE",
7070 "namespace": "NAMESPACE",
7071 "constructor": "CONSTRUCTOR",
7076 tokens
.extend(keywords
.values())
7078 def t_error(self
, t
):
7080 "Unrecognized Input",
7084 lineno
=self
.lexer
.lineno
,
7085 lexpos
=self
.lexer
.lexpos
,
7086 filename
=self
._filename
,
7091 def __init__(self
, outputdir
, lexer
=None):
7095 self
.lexer
= lex
.lex(object=self
, reflags
=re
.DOTALL
)
7098 class SqueakyCleanLogger(object):
7100 # Web IDL defines the WHITESPACE token, but doesn't actually
7101 # use it ... so far.
7102 "Token 'WHITESPACE' defined, but not used",
7103 # And that means we have an unused token
7104 "There is 1 unused token",
7105 # Web IDL defines a OtherOrComma rule that's only used in
7106 # ExtendedAttributeInner, which we don't use yet.
7107 "Rule 'OtherOrComma' defined, but not used",
7108 # And an unused rule
7109 "There is 1 unused rule",
7110 # And the OtherOrComma grammar symbol is unreachable.
7111 "Symbol 'OtherOrComma' is unreachable",
7112 # Which means the Other symbol is unreachable.
7113 "Symbol 'Other' is unreachable",
7119 def debug(self
, msg
, *args
, **kwargs
):
7124 def warning(self
, msg
, *args
, **kwargs
):
7126 msg
== "%s:%d: Rule %r defined, but not used"
7127 or msg
== "%s:%d: Rule '%s' defined, but not used"
7129 # Munge things so we don't have to hardcode filenames and
7130 # line numbers in our whitelist.
7131 whitelistmsg
= "Rule %r defined, but not used"
7132 whitelistargs
= args
[2:]
7135 whitelistargs
= args
7136 if (whitelistmsg
% whitelistargs
) not in SqueakyCleanLogger
.errorWhitelist
:
7137 self
.errors
.append(msg
% args
)
7141 def reportGrammarErrors(self
):
7143 raise WebIDLError("\n".join(self
.errors
), [])
7146 class Parser(Tokenizer
):
7147 def getLocation(self
, p
, i
):
7148 return Location(self
.lexer
, p
.lineno(i
), p
.lexpos(i
), self
._filename
)
7150 def globalScope(self
):
7151 return self
._globalScope
7153 # The p_Foo functions here must match the WebIDL spec's grammar.
7154 # It's acceptable to split things at '|' boundaries.
7155 def p_Definitions(self
, p
):
7157 Definitions : ExtendedAttributeList Definition Definitions
7161 p
[2].addExtendedAttributes(p
[1])
7168 def p_DefinitionsEmpty(self
, p
):
7174 def p_Definition(self
, p
):
7176 Definition : CallbackOrInterfaceOrMixin
7186 assert p
[1] # We might not have implemented something ...
7188 def p_CallbackOrInterfaceOrMixinCallback(self
, p
):
7190 CallbackOrInterfaceOrMixin : CALLBACK CallbackRestOrInterface
7192 if p
[2].isInterface():
7193 assert isinstance(p
[2], IDLInterface
)
7194 p
[2].setCallback(True)
7198 def p_CallbackOrInterfaceOrMixinInterfaceOrMixin(self
, p
):
7200 CallbackOrInterfaceOrMixin : INTERFACE InterfaceOrMixin
7204 def p_CallbackRestOrInterface(self
, p
):
7206 CallbackRestOrInterface : CallbackRest
7207 | CallbackConstructorRest
7213 def handleNonPartialObject(
7214 self
, location
, identifier
, constructor
, constructorArgs
, nonPartialArgs
7217 This handles non-partial objects (interfaces, namespaces and
7218 dictionaries) by checking for an existing partial object, and promoting
7219 it to non-partial as needed. The return value is the non-partial
7222 constructorArgs are all the args for the constructor except the last
7223 one: isKnownNonPartial.
7225 nonPartialArgs are the args for the setNonPartial call.
7227 # The name of the class starts with "IDL", so strip that off.
7228 # Also, starts with a capital letter after that, so nix that
7230 prettyname
= constructor
.__name
__[3:].lower()
7233 existingObj
= self
.globalScope()._lookupIdentifier
(identifier
)
7235 if not isinstance(existingObj
, constructor
):
7237 "%s has the same name as "
7238 "non-%s object" % (prettyname
.capitalize(), prettyname
),
7239 [location
, existingObj
.location
],
7241 existingObj
.setNonPartial(*nonPartialArgs
)
7243 except Exception as ex
:
7244 if isinstance(ex
, WebIDLError
):
7248 # True for isKnownNonPartial
7249 return constructor(*(constructorArgs
+ [True]))
7251 def p_InterfaceOrMixin(self
, p
):
7253 InterfaceOrMixin : InterfaceRest
7258 def p_CallbackInterface(self
, p
):
7260 CallbackInterface : INTERFACE InterfaceRest
7264 def p_InterfaceRest(self
, p
):
7266 InterfaceRest : IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON
7268 location
= self
.getLocation(p
, 1)
7269 identifier
= IDLUnresolvedIdentifier(location
, p
[1])
7273 p
[0] = self
.handleNonPartialObject(
7277 [location
, self
.globalScope(), identifier
, parent
, members
],
7278 [location
, parent
, members
],
7281 def p_InterfaceForwardDecl(self
, p
):
7283 InterfaceRest : IDENTIFIER SEMICOLON
7285 location
= self
.getLocation(p
, 1)
7286 identifier
= IDLUnresolvedIdentifier(location
, p
[1])
7289 if self
.globalScope()._lookupIdentifier
(identifier
):
7290 p
[0] = self
.globalScope()._lookupIdentifier
(identifier
)
7291 if not isinstance(p
[0], IDLExternalInterface
):
7293 "Name collision between external "
7294 "interface declaration for identifier "
7295 "%s and %s" % (identifier
.name
, p
[0]),
7296 [location
, p
[0].location
],
7299 except Exception as ex
:
7300 if isinstance(ex
, WebIDLError
):
7304 p
[0] = IDLExternalInterface(location
, self
.globalScope(), identifier
)
7306 def p_MixinRest(self
, p
):
7308 MixinRest : MIXIN IDENTIFIER LBRACE MixinMembers RBRACE SEMICOLON
7310 location
= self
.getLocation(p
, 1)
7311 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 2), p
[2])
7314 p
[0] = self
.handleNonPartialObject(
7318 [location
, self
.globalScope(), identifier
, members
],
7319 [location
, members
],
7322 def p_Namespace(self
, p
):
7324 Namespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON
7326 location
= self
.getLocation(p
, 1)
7327 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 2), p
[2])
7330 p
[0] = self
.handleNonPartialObject(
7334 [location
, self
.globalScope(), identifier
, members
],
7335 [location
, None, members
],
7338 def p_Partial(self
, p
):
7340 Partial : PARTIAL PartialDefinition
7344 def p_PartialDefinitionInterface(self
, p
):
7346 PartialDefinition : INTERFACE PartialInterfaceOrPartialMixin
7350 def p_PartialDefinition(self
, p
):
7352 PartialDefinition : PartialNamespace
7357 def handlePartialObject(
7361 nonPartialConstructor
,
7362 nonPartialConstructorArgs
,
7363 partialConstructorArgs
,
7366 This handles partial objects (interfaces, namespaces and dictionaries)
7367 by checking for an existing non-partial object, and adding ourselves to
7368 it as needed. The return value is our partial object. We use
7369 IDLPartialInterfaceOrNamespace for partial interfaces or namespaces,
7370 and IDLPartialDictionary for partial dictionaries.
7372 nonPartialConstructorArgs are all the args for the non-partial
7373 constructor except the last two: members and isKnownNonPartial.
7375 partialConstructorArgs are the arguments for the partial object
7376 constructor, except the last one (the non-partial object).
7378 # The name of the class starts with "IDL", so strip that off.
7379 # Also, starts with a capital letter after that, so nix that
7381 prettyname
= nonPartialConstructor
.__name
__[3:].lower()
7383 nonPartialObject
= None
7385 nonPartialObject
= self
.globalScope()._lookupIdentifier
(identifier
)
7386 if nonPartialObject
:
7387 if not isinstance(nonPartialObject
, nonPartialConstructor
):
7389 "Partial %s has the same name as "
7390 "non-%s object" % (prettyname
, prettyname
),
7391 [location
, nonPartialObject
.location
],
7393 except Exception as ex
:
7394 if isinstance(ex
, WebIDLError
):
7398 if not nonPartialObject
:
7399 nonPartialObject
= nonPartialConstructor(
7400 # No members, False for isKnownNonPartial
7401 *(nonPartialConstructorArgs
),
7403 isKnownNonPartial
=False
7406 partialObject
= None
7407 if isinstance(nonPartialObject
, IDLDictionary
):
7408 partialObject
= IDLPartialDictionary(
7409 *(partialConstructorArgs
+ [nonPartialObject
])
7412 nonPartialObject
, (IDLInterface
, IDLInterfaceMixin
, IDLNamespace
)
7414 partialObject
= IDLPartialInterfaceOrNamespace(
7415 *(partialConstructorArgs
+ [nonPartialObject
])
7419 "Unknown partial object type %s" % type(partialObject
), [location
]
7422 return partialObject
7424 def p_PartialInterfaceOrPartialMixin(self
, p
):
7426 PartialInterfaceOrPartialMixin : PartialInterfaceRest
7431 def p_PartialInterfaceRest(self
, p
):
7433 PartialInterfaceRest : IDENTIFIER LBRACE PartialInterfaceMembers RBRACE SEMICOLON
7435 location
= self
.getLocation(p
, 1)
7436 identifier
= IDLUnresolvedIdentifier(location
, p
[1])
7439 p
[0] = self
.handlePartialObject(
7443 [location
, self
.globalScope(), identifier
, None],
7444 [location
, identifier
, members
],
7447 def p_PartialMixinRest(self
, p
):
7449 PartialMixinRest : MIXIN IDENTIFIER LBRACE MixinMembers RBRACE SEMICOLON
7451 location
= self
.getLocation(p
, 1)
7452 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 2), p
[2])
7455 p
[0] = self
.handlePartialObject(
7459 [location
, self
.globalScope(), identifier
],
7460 [location
, identifier
, members
],
7463 def p_PartialNamespace(self
, p
):
7465 PartialNamespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON
7467 location
= self
.getLocation(p
, 1)
7468 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 2), p
[2])
7471 p
[0] = self
.handlePartialObject(
7475 [location
, self
.globalScope(), identifier
],
7476 [location
, identifier
, members
],
7479 def p_PartialDictionary(self
, p
):
7481 PartialDictionary : DICTIONARY IDENTIFIER LBRACE DictionaryMembers RBRACE SEMICOLON
7483 location
= self
.getLocation(p
, 1)
7484 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 2), p
[2])
7487 p
[0] = self
.handlePartialObject(
7491 [location
, self
.globalScope(), identifier
],
7492 [location
, identifier
, members
],
7495 def p_Inheritance(self
, p
):
7497 Inheritance : COLON ScopedName
7499 p
[0] = IDLIdentifierPlaceholder(self
.getLocation(p
, 2), p
[2])
7501 def p_InheritanceEmpty(self
, p
):
7507 def p_InterfaceMembers(self
, p
):
7509 InterfaceMembers : ExtendedAttributeList InterfaceMember InterfaceMembers
7513 assert not p
[1] or p
[2]
7514 p
[2].addExtendedAttributes(p
[1])
7518 def p_InterfaceMembersEmpty(self
, p
):
7524 def p_InterfaceMember(self
, p
):
7526 InterfaceMember : PartialInterfaceMember
7531 def p_Constructor(self
, p
):
7533 Constructor : CONSTRUCTOR LPAREN ArgumentList RPAREN SEMICOLON
7535 p
[0] = IDLConstructor(self
.getLocation(p
, 1), p
[3], "constructor")
7537 def p_PartialInterfaceMembers(self
, p
):
7539 PartialInterfaceMembers : ExtendedAttributeList PartialInterfaceMember PartialInterfaceMembers
7543 assert not p
[1] or p
[2]
7544 p
[2].addExtendedAttributes(p
[1])
7548 def p_PartialInterfaceMembersEmpty(self
, p
):
7550 PartialInterfaceMembers :
7554 def p_PartialInterfaceMember(self
, p
):
7556 PartialInterfaceMember : Const
7557 | AttributeOrOperationOrMaplikeOrSetlikeOrIterable
7561 def p_MixinMembersEmpty(self
, p
):
7567 def p_MixinMembers(self
, p
):
7569 MixinMembers : ExtendedAttributeList MixinMember MixinMembers
7573 assert not p
[1] or p
[2]
7574 p
[2].addExtendedAttributes(p
[1])
7578 def p_MixinMember(self
, p
):
7586 def p_Dictionary(self
, p
):
7588 Dictionary : DICTIONARY IDENTIFIER Inheritance LBRACE DictionaryMembers RBRACE SEMICOLON
7590 location
= self
.getLocation(p
, 1)
7591 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 2), p
[2])
7593 p
[0] = IDLDictionary(location
, self
.globalScope(), identifier
, p
[3], members
)
7595 def p_DictionaryMembers(self
, p
):
7597 DictionaryMembers : ExtendedAttributeList DictionaryMember DictionaryMembers
7601 # We're at the end of the list
7604 p
[2].addExtendedAttributes(p
[1])
7608 def p_DictionaryMemberRequired(self
, p
):
7610 DictionaryMember : REQUIRED TypeWithExtendedAttributes IDENTIFIER SEMICOLON
7612 # These quack a lot like required arguments, so just treat them that way.
7614 assert isinstance(t
, IDLType
)
7615 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 3), p
[3])
7618 self
.getLocation(p
, 3),
7624 dictionaryMember
=True,
7627 def p_DictionaryMember(self
, p
):
7629 DictionaryMember : Type IDENTIFIER Default SEMICOLON
7631 # These quack a lot like optional arguments, so just treat them that way.
7633 assert isinstance(t
, IDLType
)
7634 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 2), p
[2])
7637 # Any attributes that precede this may apply to the type, so
7638 # we configure the argument to forward type attributes down instead of producing
7641 self
.getLocation(p
, 2),
7645 defaultValue
=defaultValue
,
7647 dictionaryMember
=True,
7648 allowTypeAttributes
=True,
7651 def p_Default(self
, p
):
7653 Default : EQUALS DefaultValue
7661 def p_DefaultValue(self
, p
):
7663 DefaultValue : ConstValue
7670 assert len(p
) == 3 # Must be [] or {}
7672 p
[0] = IDLEmptySequenceValue(self
.getLocation(p
, 1))
7675 p
[0] = IDLDefaultDictionaryValue(self
.getLocation(p
, 1))
7677 def p_DefaultValueNull(self
, p
):
7681 p
[0] = IDLNullValue(self
.getLocation(p
, 1))
7683 def p_DefaultValueUndefined(self
, p
):
7685 DefaultValue : UNDEFINED
7687 p
[0] = IDLUndefinedValue(self
.getLocation(p
, 1))
7689 def p_Exception(self
, p
):
7691 Exception : EXCEPTION IDENTIFIER Inheritance LBRACE ExceptionMembers RBRACE SEMICOLON
7695 def p_Enum(self
, p
):
7697 Enum : ENUM IDENTIFIER LBRACE EnumValueList RBRACE SEMICOLON
7699 location
= self
.getLocation(p
, 1)
7700 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 2), p
[2])
7704 p
[0] = IDLEnum(location
, self
.globalScope(), identifier
, values
)
7706 def p_EnumValueList(self
, p
):
7708 EnumValueList : STRING EnumValueListComma
7713 def p_EnumValueListComma(self
, p
):
7715 EnumValueListComma : COMMA EnumValueListString
7719 def p_EnumValueListCommaEmpty(self
, p
):
7721 EnumValueListComma :
7725 def p_EnumValueListString(self
, p
):
7727 EnumValueListString : STRING EnumValueListComma
7732 def p_EnumValueListStringEmpty(self
, p
):
7734 EnumValueListString :
7738 def p_CallbackRest(self
, p
):
7740 CallbackRest : IDENTIFIER EQUALS Type LPAREN ArgumentList RPAREN SEMICOLON
7742 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 1), p
[1])
7744 self
.getLocation(p
, 1),
7749 isConstructor
=False,
7752 def p_CallbackConstructorRest(self
, p
):
7754 CallbackConstructorRest : CONSTRUCTOR IDENTIFIER EQUALS Type LPAREN ArgumentList RPAREN SEMICOLON
7756 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 2), p
[2])
7758 self
.getLocation(p
, 2),
7766 def p_ExceptionMembers(self
, p
):
7768 ExceptionMembers : ExtendedAttributeList ExceptionMember ExceptionMembers
7773 def p_Typedef(self
, p
):
7775 Typedef : TYPEDEF TypeWithExtendedAttributes IDENTIFIER SEMICOLON
7777 typedef
= IDLTypedef(self
.getLocation(p
, 1), self
.globalScope(), p
[2], p
[3])
7780 def p_IncludesStatement(self
, p
):
7782 IncludesStatement : ScopedName INCLUDES ScopedName SEMICOLON
7784 assert p
[2] == "includes"
7785 interface
= IDLIdentifierPlaceholder(self
.getLocation(p
, 1), p
[1])
7786 mixin
= IDLIdentifierPlaceholder(self
.getLocation(p
, 3), p
[3])
7787 p
[0] = IDLIncludesStatement(self
.getLocation(p
, 1), interface
, mixin
)
7789 def p_Const(self
, p
):
7791 Const : CONST ConstType IDENTIFIER EQUALS ConstValue SEMICOLON
7793 location
= self
.getLocation(p
, 1)
7795 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 3), p
[3])
7797 p
[0] = IDLConst(location
, identifier
, type, value
)
7799 def p_ConstValueBoolean(self
, p
):
7801 ConstValue : BooleanLiteral
7803 location
= self
.getLocation(p
, 1)
7804 booleanType
= BuiltinTypes
[IDLBuiltinType
.Types
.boolean
]
7805 p
[0] = IDLValue(location
, booleanType
, p
[1])
7807 def p_ConstValueInteger(self
, p
):
7809 ConstValue : INTEGER
7811 location
= self
.getLocation(p
, 1)
7813 # We don't know ahead of time what type the integer literal is.
7814 # Determine the smallest type it could possibly fit in and use that.
7815 integerType
= matchIntegerValueToType(p
[1])
7816 if integerType
is None:
7817 raise WebIDLError("Integer literal out of range", [location
])
7819 p
[0] = IDLValue(location
, integerType
, p
[1])
7821 def p_ConstValueFloat(self
, p
):
7823 ConstValue : FLOATLITERAL
7825 location
= self
.getLocation(p
, 1)
7827 location
, BuiltinTypes
[IDLBuiltinType
.Types
.unrestricted_float
], p
[1]
7830 def p_ConstValueString(self
, p
):
7834 location
= self
.getLocation(p
, 1)
7835 stringType
= BuiltinTypes
[IDLBuiltinType
.Types
.domstring
]
7836 p
[0] = IDLValue(location
, stringType
, p
[1])
7838 def p_BooleanLiteralTrue(self
, p
):
7840 BooleanLiteral : TRUE
7844 def p_BooleanLiteralFalse(self
, p
):
7846 BooleanLiteral : FALSE
7850 def p_AttributeOrOperationOrMaplikeOrSetlikeOrIterable(self
, p
):
7852 AttributeOrOperationOrMaplikeOrSetlikeOrIterable : Attribute
7861 def p_Iterable(self
, p
):
7863 Iterable : ITERABLE LT TypeWithExtendedAttributes GT SEMICOLON
7864 | ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON
7866 location
= self
.getLocation(p
, 2)
7867 identifier
= IDLUnresolvedIdentifier(
7868 location
, "__iterable", allowDoubleUnderscore
=True
7877 p
[0] = IDLIterable(location
, identifier
, keyType
, valueType
, self
.globalScope())
7879 def p_AsyncIterable(self
, p
):
7881 AsyncIterable : ASYNC ITERABLE LT TypeWithExtendedAttributes GT SEMICOLON
7882 | ASYNC ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON
7883 | ASYNC ITERABLE LT TypeWithExtendedAttributes GT LPAREN ArgumentList RPAREN SEMICOLON
7884 | ASYNC ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT LPAREN ArgumentList RPAREN SEMICOLON
7886 location
= self
.getLocation(p
, 2)
7887 identifier
= IDLUnresolvedIdentifier(
7888 location
, "__iterable", allowDoubleUnderscore
=True
7907 p
[0] = IDLAsyncIterable(
7908 location
, identifier
, keyType
, valueType
, argList
, self
.globalScope()
7911 def p_Setlike(self
, p
):
7913 Setlike : ReadOnly SETLIKE LT TypeWithExtendedAttributes GT SEMICOLON
7916 maplikeOrSetlikeType
= p
[2]
7917 location
= self
.getLocation(p
, 2)
7918 identifier
= IDLUnresolvedIdentifier(
7919 location
, "__setlike", allowDoubleUnderscore
=True
7923 p
[0] = IDLMaplikeOrSetlike(
7924 location
, identifier
, maplikeOrSetlikeType
, readonly
, keyType
, valueType
7927 def p_Maplike(self
, p
):
7929 Maplike : ReadOnly MAPLIKE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON
7932 maplikeOrSetlikeType
= p
[2]
7933 location
= self
.getLocation(p
, 2)
7934 identifier
= IDLUnresolvedIdentifier(
7935 location
, "__maplike", allowDoubleUnderscore
=True
7939 p
[0] = IDLMaplikeOrSetlike(
7940 location
, identifier
, maplikeOrSetlikeType
, readonly
, keyType
, valueType
7943 def p_AttributeWithQualifier(self
, p
):
7945 Attribute : Qualifier AttributeRest
7947 static
= IDLInterfaceMember
.Special
.Static
in p
[1]
7948 stringifier
= IDLInterfaceMember
.Special
.Stringifier
in p
[1]
7949 (location
, identifier
, type, readonly
) = p
[2]
7950 p
[0] = IDLAttribute(
7951 location
, identifier
, type, readonly
, static
=static
, stringifier
=stringifier
7954 def p_AttributeInherited(self
, p
):
7956 Attribute : INHERIT AttributeRest
7958 (location
, identifier
, type, readonly
) = p
[2]
7959 p
[0] = IDLAttribute(location
, identifier
, type, readonly
, inherit
=True)
7961 def p_Attribute(self
, p
):
7963 Attribute : AttributeRest
7965 (location
, identifier
, type, readonly
) = p
[1]
7966 p
[0] = IDLAttribute(location
, identifier
, type, readonly
, inherit
=False)
7968 def p_AttributeRest(self
, p
):
7970 AttributeRest : ReadOnly ATTRIBUTE TypeWithExtendedAttributes AttributeName SEMICOLON
7972 location
= self
.getLocation(p
, 2)
7975 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 4), p
[4])
7976 p
[0] = (location
, identifier
, t
, readonly
)
7978 def p_ReadOnly(self
, p
):
7984 def p_ReadOnlyEmpty(self
, p
):
7990 def p_Operation(self
, p
):
7992 Operation : Qualifiers OperationRest
7996 # Disallow duplicates in the qualifier set
7997 if not len(set(qualifiers
)) == len(qualifiers
):
7999 "Duplicate qualifiers are not allowed", [self
.getLocation(p
, 1)]
8002 static
= IDLInterfaceMember
.Special
.Static
in p
[1]
8003 # If static is there that's all that's allowed. This is disallowed
8004 # by the parser, so we can assert here.
8005 assert not static
or len(qualifiers
) == 1
8007 stringifier
= IDLInterfaceMember
.Special
.Stringifier
in p
[1]
8008 # If stringifier is there that's all that's allowed. This is disallowed
8009 # by the parser, so we can assert here.
8010 assert not stringifier
or len(qualifiers
) == 1
8012 getter
= True if IDLMethod
.Special
.Getter
in p
[1] else False
8013 setter
= True if IDLMethod
.Special
.Setter
in p
[1] else False
8014 deleter
= True if IDLMethod
.Special
.Deleter
in p
[1] else False
8015 legacycaller
= True if IDLMethod
.Special
.LegacyCaller
in p
[1] else False
8017 if getter
or deleter
:
8020 "getter and deleter are incompatible with setter",
8021 [self
.getLocation(p
, 1)],
8024 (returnType
, identifier
, arguments
) = p
[2]
8026 assert isinstance(returnType
, IDLType
)
8028 specialType
= IDLMethod
.NamedOrIndexed
.Neither
8030 if getter
or deleter
:
8031 if len(arguments
) != 1:
8033 "%s has wrong number of arguments"
8034 % ("getter" if getter
else "deleter"),
8035 [self
.getLocation(p
, 2)],
8037 argType
= arguments
[0].type
8038 if argType
== BuiltinTypes
[IDLBuiltinType
.Types
.domstring
]:
8039 specialType
= IDLMethod
.NamedOrIndexed
.Named
8040 elif argType
== BuiltinTypes
[IDLBuiltinType
.Types
.unsigned_long
]:
8041 specialType
= IDLMethod
.NamedOrIndexed
.Indexed
8044 "There is no such thing as an indexed deleter.",
8045 [self
.getLocation(p
, 1)],
8049 "%s has wrong argument type (must be DOMString or UnsignedLong)"
8050 % ("getter" if getter
else "deleter"),
8051 [arguments
[0].location
],
8053 if arguments
[0].optional
or arguments
[0].variadic
:
8055 "%s cannot have %s argument"
8057 "getter" if getter
else "deleter",
8058 "optional" if arguments
[0].optional
else "variadic",
8060 [arguments
[0].location
],
8063 if returnType
.isUndefined():
8065 "getter cannot have undefined return type", [self
.getLocation(p
, 2)]
8068 if len(arguments
) != 2:
8070 "setter has wrong number of arguments", [self
.getLocation(p
, 2)]
8072 argType
= arguments
[0].type
8073 if argType
== BuiltinTypes
[IDLBuiltinType
.Types
.domstring
]:
8074 specialType
= IDLMethod
.NamedOrIndexed
.Named
8075 elif argType
== BuiltinTypes
[IDLBuiltinType
.Types
.unsigned_long
]:
8076 specialType
= IDLMethod
.NamedOrIndexed
.Indexed
8079 "settter has wrong argument type (must be DOMString or UnsignedLong)",
8080 [arguments
[0].location
],
8082 if arguments
[0].optional
or arguments
[0].variadic
:
8084 "setter cannot have %s argument"
8085 % ("optional" if arguments
[0].optional
else "variadic"),
8086 [arguments
[0].location
],
8088 if arguments
[1].optional
or arguments
[1].variadic
:
8090 "setter cannot have %s argument"
8091 % ("optional" if arguments
[1].optional
else "variadic"),
8092 [arguments
[1].location
],
8096 if len(arguments
) != 0:
8098 "stringifier has wrong number of arguments",
8099 [self
.getLocation(p
, 2)],
8101 if not returnType
.isDOMString():
8103 "stringifier must have DOMString return type",
8104 [self
.getLocation(p
, 2)],
8107 # identifier might be None. This is only permitted for special methods.
8113 and not legacycaller
8117 "Identifier required for non-special methods",
8118 [self
.getLocation(p
, 2)],
8121 location
= BuiltinLocation("<auto-generated-identifier>")
8122 identifier
= IDLUnresolvedIdentifier(
8127 if specialType
== IDLMethod
.NamedOrIndexed
.Named
8129 if specialType
== IDLMethod
.NamedOrIndexed
.Indexed
8131 "getter" if getter
else "",
8132 "setter" if setter
else "",
8133 "deleter" if deleter
else "",
8134 "legacycaller" if legacycaller
else "",
8135 "stringifier" if stringifier
else "",
8137 allowDoubleUnderscore
=True,
8141 self
.getLocation(p
, 2),
8149 specialType
=specialType
,
8150 legacycaller
=legacycaller
,
8151 stringifier
=stringifier
,
8155 def p_Stringifier(self
, p
):
8157 Operation : STRINGIFIER SEMICOLON
8159 identifier
= IDLUnresolvedIdentifier(
8160 BuiltinLocation("<auto-generated-identifier>"),
8162 allowDoubleUnderscore
=True,
8165 self
.getLocation(p
, 1),
8167 returnType
=BuiltinTypes
[IDLBuiltinType
.Types
.domstring
],
8173 def p_QualifierStatic(self
, p
):
8177 p
[0] = [IDLInterfaceMember
.Special
.Static
]
8179 def p_QualifierStringifier(self
, p
):
8181 Qualifier : STRINGIFIER
8183 p
[0] = [IDLInterfaceMember
.Special
.Stringifier
]
8185 def p_Qualifiers(self
, p
):
8187 Qualifiers : Qualifier
8192 def p_Specials(self
, p
):
8194 Specials : Special Specials
8199 def p_SpecialsEmpty(self
, p
):
8205 def p_SpecialGetter(self
, p
):
8209 p
[0] = IDLMethod
.Special
.Getter
8211 def p_SpecialSetter(self
, p
):
8215 p
[0] = IDLMethod
.Special
.Setter
8217 def p_SpecialDeleter(self
, p
):
8221 p
[0] = IDLMethod
.Special
.Deleter
8223 def p_SpecialLegacyCaller(self
, p
):
8225 Special : LEGACYCALLER
8227 p
[0] = IDLMethod
.Special
.LegacyCaller
8229 def p_OperationRest(self
, p
):
8231 OperationRest : Type OptionalIdentifier LPAREN ArgumentList RPAREN SEMICOLON
8233 p
[0] = (p
[1], p
[2], p
[4])
8235 def p_OptionalIdentifier(self
, p
):
8237 OptionalIdentifier : IDENTIFIER
8239 p
[0] = IDLUnresolvedIdentifier(self
.getLocation(p
, 1), p
[1])
8241 def p_OptionalIdentifierEmpty(self
, p
):
8243 OptionalIdentifier :
8247 def p_ArgumentList(self
, p
):
8249 ArgumentList : Argument Arguments
8251 p
[0] = [p
[1]] if p
[1] else []
8254 def p_ArgumentListEmpty(self
, p
):
8260 def p_Arguments(self
, p
):
8262 Arguments : COMMA Argument Arguments
8264 p
[0] = [p
[2]] if p
[2] else []
8267 def p_ArgumentsEmpty(self
, p
):
8273 def p_Argument(self
, p
):
8275 Argument : ExtendedAttributeList ArgumentRest
8278 p
[0].addExtendedAttributes(p
[1])
8280 def p_ArgumentRestOptional(self
, p
):
8282 ArgumentRest : OPTIONAL TypeWithExtendedAttributes ArgumentName Default
8285 assert isinstance(t
, IDLType
)
8286 # Arg names can be reserved identifiers
8287 identifier
= IDLUnresolvedIdentifier(
8288 self
.getLocation(p
, 3), p
[3], allowForbidden
=True
8293 # We can't test t.isAny() here and give it a default value as needed,
8294 # since at this point t is not a fully resolved type yet (e.g. it might
8295 # be a typedef). We'll handle the 'any' case in IDLArgument.complete.
8298 self
.getLocation(p
, 3), identifier
, t
, True, defaultValue
, False
8301 def p_ArgumentRest(self
, p
):
8303 ArgumentRest : Type Ellipsis ArgumentName
8306 assert isinstance(t
, IDLType
)
8307 # Arg names can be reserved identifiers
8308 identifier
= IDLUnresolvedIdentifier(
8309 self
.getLocation(p
, 3), p
[3], allowForbidden
=True
8314 # We can't test t.isAny() here and give it a default value as needed,
8315 # since at this point t is not a fully resolved type yet (e.g. it might
8316 # be a typedef). We'll handle the 'any' case in IDLArgument.complete.
8318 # variadic implies optional
8319 # Any attributes that precede this may apply to the type, so
8320 # we configure the argument to forward type attributes down instead of producing
8323 self
.getLocation(p
, 3),
8329 allowTypeAttributes
=True,
8332 def p_ArgumentName(self
, p
):
8334 ArgumentName : IDENTIFIER
8335 | ArgumentNameKeyword
8339 def p_ArgumentNameKeyword(self
, p
):
8341 ArgumentNameKeyword : ASYNC
8372 def p_AttributeName(self
, p
):
8374 AttributeName : IDENTIFIER
8375 | AttributeNameKeyword
8379 def p_AttributeNameKeyword(self
, p
):
8381 AttributeNameKeyword : ASYNC
8386 def p_Ellipsis(self
, p
):
8392 def p_EllipsisEmpty(self
, p
):
8398 def p_ExceptionMember(self
, p
):
8400 ExceptionMember : Const
8405 def p_ExceptionField(self
, p
):
8407 ExceptionField : Type IDENTIFIER SEMICOLON
8411 def p_ExtendedAttributeList(self
, p
):
8413 ExtendedAttributeList : LBRACKET ExtendedAttribute ExtendedAttributes RBRACKET
8419 def p_ExtendedAttributeListEmpty(self
, p
):
8421 ExtendedAttributeList :
8425 def p_ExtendedAttribute(self
, p
):
8427 ExtendedAttribute : ExtendedAttributeNoArgs
8428 | ExtendedAttributeArgList
8429 | ExtendedAttributeIdent
8430 | ExtendedAttributeWildcard
8431 | ExtendedAttributeNamedArgList
8432 | ExtendedAttributeIdentList
8434 p
[0] = IDLExtendedAttribute(self
.getLocation(p
, 1), p
[1])
8436 def p_ExtendedAttributeEmpty(self
, p
):
8442 def p_ExtendedAttributes(self
, p
):
8444 ExtendedAttributes : COMMA ExtendedAttribute ExtendedAttributes
8446 p
[0] = [p
[2]] if p
[2] else []
8449 def p_ExtendedAttributesEmpty(self
, p
):
8451 ExtendedAttributes :
8455 def p_Other(self
, p
):
8496 | ArgumentNameKeyword
8500 def p_OtherOrComma(self
, p
):
8502 OtherOrComma : Other
8507 def p_TypeSingleType(self
, p
):
8513 def p_TypeUnionType(self
, p
):
8515 Type : UnionType Null
8517 p
[0] = self
.handleNullable(p
[1], p
[2])
8519 def p_TypeWithExtendedAttributes(self
, p
):
8521 TypeWithExtendedAttributes : ExtendedAttributeList Type
8523 p
[0] = p
[2].withExtendedAttributes(p
[1])
8525 def p_SingleTypeDistinguishableType(self
, p
):
8527 SingleType : DistinguishableType
8531 def p_SingleTypeAnyType(self
, p
):
8535 p
[0] = BuiltinTypes
[IDLBuiltinType
.Types
.any
]
8537 def p_SingleTypePromiseType(self
, p
):
8539 SingleType : PROMISE LT Type GT
8541 p
[0] = IDLPromiseType(self
.getLocation(p
, 1), p
[3])
8543 def p_UnionType(self
, p
):
8545 UnionType : LPAREN UnionMemberType OR UnionMemberType UnionMemberTypes RPAREN
8547 types
= [p
[2], p
[4]]
8549 p
[0] = IDLUnionType(self
.getLocation(p
, 1), types
)
8551 def p_UnionMemberTypeDistinguishableType(self
, p
):
8553 UnionMemberType : ExtendedAttributeList DistinguishableType
8555 p
[0] = p
[2].withExtendedAttributes(p
[1])
8557 def p_UnionMemberType(self
, p
):
8559 UnionMemberType : UnionType Null
8561 p
[0] = self
.handleNullable(p
[1], p
[2])
8563 def p_UnionMemberTypes(self
, p
):
8565 UnionMemberTypes : OR UnionMemberType UnionMemberTypes
8570 def p_UnionMemberTypesEmpty(self
, p
):
8576 def p_DistinguishableType(self
, p
):
8578 DistinguishableType : PrimitiveType Null
8583 if p
[1] == "object":
8584 type = BuiltinTypes
[IDLBuiltinType
.Types
.object]
8585 elif p
[1] == "ArrayBuffer":
8586 type = BuiltinTypes
[IDLBuiltinType
.Types
.ArrayBuffer
]
8587 elif p
[1] == "undefined":
8588 type = BuiltinTypes
[IDLBuiltinType
.Types
.undefined
]
8590 type = BuiltinTypes
[p
[1]]
8592 p
[0] = self
.handleNullable(type, p
[2])
8594 def p_DistinguishableTypeStringType(self
, p
):
8596 DistinguishableType : StringType Null
8598 p
[0] = self
.handleNullable(p
[1], p
[2])
8600 def p_DistinguishableTypeSequenceType(self
, p
):
8602 DistinguishableType : SEQUENCE LT TypeWithExtendedAttributes GT Null
8605 type = IDLSequenceType(self
.getLocation(p
, 1), innerType
)
8606 p
[0] = self
.handleNullable(type, p
[5])
8608 def p_DistinguishableTypeRecordType(self
, p
):
8610 DistinguishableType : RECORD LT StringType COMMA TypeWithExtendedAttributes GT Null
8614 type = IDLRecordType(self
.getLocation(p
, 1), keyType
, valueType
)
8615 p
[0] = self
.handleNullable(type, p
[7])
8617 def p_DistinguishableTypeObservableArrayType(self
, p
):
8619 DistinguishableType : OBSERVABLEARRAY LT TypeWithExtendedAttributes GT Null
8622 type = IDLObservableArrayType(self
.getLocation(p
, 1), innerType
)
8623 p
[0] = self
.handleNullable(type, p
[5])
8625 def p_DistinguishableTypeScopedName(self
, p
):
8627 DistinguishableType : ScopedName Null
8629 assert isinstance(p
[1], IDLUnresolvedIdentifier
)
8631 if p
[1].name
== "Promise":
8633 "Promise used without saying what it's " "parametrized over",
8634 [self
.getLocation(p
, 1)],
8640 if self
.globalScope()._lookupIdentifier
(p
[1]):
8641 obj
= self
.globalScope()._lookupIdentifier
(p
[1])
8642 assert not obj
.isType()
8644 type = IDLTypedefType(
8645 self
.getLocation(p
, 1), obj
.innerType
, obj
.identifier
.name
8647 elif obj
.isCallback() and not obj
.isInterface():
8648 type = IDLCallbackType(self
.getLocation(p
, 1), obj
)
8650 type = IDLWrapperType(self
.getLocation(p
, 1), p
[1])
8651 p
[0] = self
.handleNullable(type, p
[2])
8656 type = IDLUnresolvedType(self
.getLocation(p
, 1), p
[1])
8657 p
[0] = self
.handleNullable(type, p
[2])
8659 def p_ConstType(self
, p
):
8661 ConstType : PrimitiveType
8663 p
[0] = BuiltinTypes
[p
[1]]
8665 def p_ConstTypeIdentifier(self
, p
):
8667 ConstType : IDENTIFIER
8669 identifier
= IDLUnresolvedIdentifier(self
.getLocation(p
, 1), p
[1])
8671 p
[0] = IDLUnresolvedType(self
.getLocation(p
, 1), identifier
)
8673 def p_PrimitiveTypeUint(self
, p
):
8675 PrimitiveType : UnsignedIntegerType
8679 def p_PrimitiveTypeBoolean(self
, p
):
8681 PrimitiveType : BOOLEAN
8683 p
[0] = IDLBuiltinType
.Types
.boolean
8685 def p_PrimitiveTypeByte(self
, p
):
8687 PrimitiveType : BYTE
8689 p
[0] = IDLBuiltinType
.Types
.byte
8691 def p_PrimitiveTypeOctet(self
, p
):
8693 PrimitiveType : OCTET
8695 p
[0] = IDLBuiltinType
.Types
.octet
8697 def p_PrimitiveTypeFloat(self
, p
):
8699 PrimitiveType : FLOAT
8701 p
[0] = IDLBuiltinType
.Types
.float
8703 def p_PrimitiveTypeUnrestictedFloat(self
, p
):
8705 PrimitiveType : UNRESTRICTED FLOAT
8707 p
[0] = IDLBuiltinType
.Types
.unrestricted_float
8709 def p_PrimitiveTypeDouble(self
, p
):
8711 PrimitiveType : DOUBLE
8713 p
[0] = IDLBuiltinType
.Types
.double
8715 def p_PrimitiveTypeUnrestictedDouble(self
, p
):
8717 PrimitiveType : UNRESTRICTED DOUBLE
8719 p
[0] = IDLBuiltinType
.Types
.unrestricted_double
8721 def p_StringType(self
, p
):
8723 StringType : BuiltinStringType
8725 p
[0] = BuiltinTypes
[p
[1]]
8727 def p_BuiltinStringTypeDOMString(self
, p
):
8729 BuiltinStringType : DOMSTRING
8731 p
[0] = IDLBuiltinType
.Types
.domstring
8733 def p_BuiltinStringTypeBytestring(self
, p
):
8735 BuiltinStringType : BYTESTRING
8737 p
[0] = IDLBuiltinType
.Types
.bytestring
8739 def p_BuiltinStringTypeUSVString(self
, p
):
8741 BuiltinStringType : USVSTRING
8743 p
[0] = IDLBuiltinType
.Types
.usvstring
8745 def p_BuiltinStringTypeUTF8String(self
, p
):
8747 BuiltinStringType : UTF8STRING
8749 p
[0] = IDLBuiltinType
.Types
.utf8string
8751 def p_BuiltinStringTypeJSString(self
, p
):
8753 BuiltinStringType : JSSTRING
8755 p
[0] = IDLBuiltinType
.Types
.jsstring
8757 def p_UnsignedIntegerTypeUnsigned(self
, p
):
8759 UnsignedIntegerType : UNSIGNED IntegerType
8761 # Adding one to a given signed integer type gets you the unsigned type:
8764 def p_UnsignedIntegerType(self
, p
):
8766 UnsignedIntegerType : IntegerType
8770 def p_IntegerTypeShort(self
, p
):
8774 p
[0] = IDLBuiltinType
.Types
.short
8776 def p_IntegerTypeLong(self
, p
):
8778 IntegerType : LONG OptionalLong
8781 p
[0] = IDLBuiltinType
.Types
.long_long
8783 p
[0] = IDLBuiltinType
.Types
.long
8785 def p_OptionalLong(self
, p
):
8791 def p_OptionalLongEmpty(self
, p
):
8797 def p_Null(self
, p
):
8803 p
[0] = self
.getLocation(p
, 1)
8807 def p_ScopedName(self
, p
):
8809 ScopedName : AbsoluteScopedName
8810 | RelativeScopedName
8814 def p_AbsoluteScopedName(self
, p
):
8816 AbsoluteScopedName : SCOPE IDENTIFIER ScopedNameParts
8821 def p_RelativeScopedName(self
, p
):
8823 RelativeScopedName : IDENTIFIER ScopedNameParts
8825 assert not p
[2] # Not implemented!
8827 p
[0] = IDLUnresolvedIdentifier(self
.getLocation(p
, 1), p
[1])
8829 def p_ScopedNameParts(self
, p
):
8831 ScopedNameParts : SCOPE IDENTIFIER ScopedNameParts
8836 def p_ScopedNamePartsEmpty(self
, p
):
8842 def p_ExtendedAttributeNoArgs(self
, p
):
8844 ExtendedAttributeNoArgs : IDENTIFIER
8848 def p_ExtendedAttributeArgList(self
, p
):
8850 ExtendedAttributeArgList : IDENTIFIER LPAREN ArgumentList RPAREN
8854 def p_ExtendedAttributeIdent(self
, p
):
8856 ExtendedAttributeIdent : IDENTIFIER EQUALS STRING
8857 | IDENTIFIER EQUALS IDENTIFIER
8861 def p_ExtendedAttributeWildcard(self
, p
):
8863 ExtendedAttributeWildcard : IDENTIFIER EQUALS ASTERISK
8867 def p_ExtendedAttributeNamedArgList(self
, p
):
8869 ExtendedAttributeNamedArgList : IDENTIFIER EQUALS IDENTIFIER LPAREN ArgumentList RPAREN
8871 p
[0] = (p
[1], p
[3], p
[5])
8873 def p_ExtendedAttributeIdentList(self
, p
):
8875 ExtendedAttributeIdentList : IDENTIFIER EQUALS LPAREN IdentifierList RPAREN
8879 def p_IdentifierList(self
, p
):
8881 IdentifierList : IDENTIFIER Identifiers
8884 # This is only used for identifier-list-valued extended attributes, and if
8885 # we're going to restrict to IDENTIFIER here we should at least allow
8886 # escaping with leading '_' as usual for identifiers.
8890 idents
.insert(0, ident
)
8893 def p_IdentifiersList(self
, p
):
8895 Identifiers : COMMA IDENTIFIER Identifiers
8898 # This is only used for identifier-list-valued extended attributes, and if
8899 # we're going to restrict to IDENTIFIER here we should at least allow
8900 # escaping with leading '_' as usual for identifiers.
8904 idents
.insert(0, ident
)
8907 def p_IdentifiersEmpty(self
, p
):
8913 def p_error(self
, p
):
8917 "Syntax Error at end of file. Possibly due to "
8918 "missing semicolon(;), braces(}) or both"
8925 [Location(self
.lexer
, p
.lineno
, p
.lexpos
, self
._filename
)],
8928 def __init__(self
, outputdir
="", lexer
=None):
8929 Tokenizer
.__init
__(self
, outputdir
, lexer
)
8931 logger
= SqueakyCleanLogger()
8933 self
.parser
= yacc
.yacc(
8935 outputdir
=outputdir
,
8938 # Pickling the grammar is a speedup in
8939 # some cases (older Python?) but a
8940 # significant slowdown in others.
8941 # We're not pickling for now, until it
8942 # becomes a speedup again.
8943 # , picklefile='WebIDLGrammar.pkl'
8946 logger
.reportGrammarErrors()
8948 self
._globalScope
= IDLScope(BuiltinLocation("<Global Scope>"), None, None)
8949 self
._installBuiltins
(self
._globalScope
)
8950 self
._productions
= []
8952 self
._filename
= "<builtin>"
8953 self
.lexer
.input(Parser
._builtins
)
8954 self
._filename
= None
8956 self
.parser
.parse(lexer
=self
.lexer
, tracking
=True)
8958 def _installBuiltins(self
, scope
):
8959 assert isinstance(scope
, IDLScope
)
8961 # range omits the last value.
8963 IDLBuiltinType
.Types
.ArrayBuffer
, IDLBuiltinType
.Types
.Float64Array
+ 1
8965 builtin
= BuiltinTypes
[x
]
8967 IDLTypedef(BuiltinLocation("<builtin type>"), scope
, builtin
, name
)
8970 def handleNullable(type, questionMarkLocation
):
8971 if questionMarkLocation
is not None:
8972 type = IDLNullableType(questionMarkLocation
, type)
8976 def parse(self
, t
, filename
=None):
8979 # for tok in iter(self.lexer.token, None):
8982 self
._filename
= filename
8983 self
._productions
.extend(self
.parser
.parse(lexer
=self
.lexer
, tracking
=True))
8984 self
._filename
= None
8987 # If we have interfaces that are iterable, create their
8988 # iterator interfaces and add them to the productions array.
8989 interfaceStatements
= []
8990 for p
in self
._productions
:
8991 if isinstance(p
, IDLInterface
):
8992 interfaceStatements
.append(p
)
8994 for iface
in interfaceStatements
:
8996 # We haven't run finish() on the interface yet, so we don't know
8997 # whether our interface is maplike/setlike/iterable or not. This
8998 # means we have to loop through the members to see if we have an
9000 for m
in iface
.members
:
9001 if isinstance(m
, (IDLIterable
, IDLAsyncIterable
)):
9004 if iterable
and (iterable
.isPairIterator() or iterable
.isAsyncIterable()):
9006 def simpleExtendedAttr(str):
9007 return IDLExtendedAttribute(iface
.location
, (str,))
9009 if isinstance(iterable
, IDLAsyncIterable
):
9010 nextReturnType
= IDLPromiseType(
9011 iterable
.location
, BuiltinTypes
[IDLBuiltinType
.Types
.any
]
9014 nextReturnType
= BuiltinTypes
[IDLBuiltinType
.Types
.object]
9015 nextMethod
= IDLMethod(
9017 IDLUnresolvedIdentifier(iterable
.location
, "next"),
9021 nextMethod
.addExtendedAttributes([simpleExtendedAttr("Throws")])
9023 methods
= [nextMethod
]
9025 if iterable
.getExtendedAttribute("GenerateReturnMethod"):
9026 assert isinstance(iterable
, IDLAsyncIterable
)
9028 returnMethod
= IDLMethod(
9030 IDLUnresolvedIdentifier(iterable
.location
, "return"),
9032 iterable
.location
, BuiltinTypes
[IDLBuiltinType
.Types
.any
]
9037 IDLUnresolvedIdentifier(
9038 BuiltinLocation("<auto-generated-identifier>"),
9041 BuiltinTypes
[IDLBuiltinType
.Types
.any
],
9046 returnMethod
.addExtendedAttributes([simpleExtendedAttr("Throws")])
9047 methods
.append(returnMethod
)
9049 if iterable
.isIterable():
9050 itr_suffix
= "Iterator"
9052 itr_suffix
= "AsyncIterator"
9053 itr_ident
= IDLUnresolvedIdentifier(
9054 iface
.location
, iface
.identifier
.name
+ itr_suffix
9056 if iterable
.isIterable():
9057 classNameOverride
= iface
.identifier
.name
+ " Iterator"
9058 elif iterable
.isAsyncIterable():
9059 classNameOverride
= iface
.identifier
.name
+ " AsyncIterator"
9060 itr_iface
= IDLInterface(
9066 isKnownNonPartial
=True,
9067 classNameOverride
=classNameOverride
,
9069 itr_iface
.addExtendedAttributes(
9070 [simpleExtendedAttr("LegacyNoInterfaceObject")]
9072 # Make sure the exposure set for the iterator interface is the
9073 # same as the exposure set for the iterable interface, because
9074 # we're going to generate methods on the iterable that return
9075 # instances of the iterator.
9076 itr_iface
._exposureGlobalNames
= set(iface
._exposureGlobalNames
)
9077 # Always append generated iterable interfaces after the
9078 # interface they're a member of, otherwise nativeType generation
9079 # won't work correctly.
9080 if iterable
.isIterable():
9081 itr_iface
.iterableInterface
= iface
9083 itr_iface
.asyncIterableInterface
= iface
9084 self
._productions
.append(itr_iface
)
9085 iterable
.iteratorType
= IDLWrapperType(iface
.location
, itr_iface
)
9087 # Make sure we finish IDLIncludesStatements before we finish the
9089 # XXX khuey hates this bit and wants to nuke it from orbit.
9090 includesStatements
= [
9091 p
for p
in self
._productions
if isinstance(p
, IDLIncludesStatement
)
9094 p
for p
in self
._productions
if not isinstance(p
, IDLIncludesStatement
)
9096 for production
in includesStatements
:
9097 production
.finish(self
.globalScope())
9098 for production
in otherStatements
:
9099 production
.finish(self
.globalScope())
9101 # Do any post-finish validation we need to do
9102 for production
in self
._productions
:
9103 production
.validate()
9105 # De-duplicate self._productions, without modifying its order.
9108 for p
in self
._productions
:
9115 return Parser(lexer
=self
.lexer
)
9117 # Builtin IDL defined by WebIDL
9119 typedef (ArrayBufferView or ArrayBuffer) BufferSource;
9125 from optparse
import OptionParser
9127 usageString
= "usage: %prog [options] files"
9128 o
= OptionParser(usage
=usageString
)
9133 help="Directory in which to cache lex/parse tables.",
9137 action
="store_true",
9139 help="When an error happens, display the Python traceback.",
9141 (options
, args
) = o
.parse_args()
9144 o
.error(usageString
)
9147 baseDir
= os
.getcwd()
9150 parser
= Parser(options
.cachedir
)
9152 for filename
in fileList
:
9153 fullPath
= os
.path
.normpath(os
.path
.join(baseDir
, filename
))
9154 f
= open(fullPath
, "rb")
9155 lines
= f
.readlines()
9158 parser
.parse("".join(lines
), fullPath
)
9160 except WebIDLError
as e
:
9161 if options
.verbose_errors
:
9162 traceback
.print_exc()
9167 if __name__
== "__main__":