mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Update the WebIDL parser.
This commit is contained in:
parent
2382d71242
commit
4157a2b02b
5 changed files with 339 additions and 105 deletions
|
@ -204,7 +204,7 @@ class IDLObject(object):
|
|||
deps.add(self.filename())
|
||||
|
||||
for d in self._getDependentObjects():
|
||||
deps = deps.union(d.getDeps(visited))
|
||||
deps.update(d.getDeps(visited))
|
||||
|
||||
return deps
|
||||
|
||||
|
@ -338,7 +338,10 @@ class IDLUnresolvedIdentifier(IDLObject):
|
|||
|
||||
assert len(name) > 0
|
||||
|
||||
if name[:2] == "__" and name != "__content" and name != "___noSuchMethod__" and not allowDoubleUnderscore:
|
||||
if name == "__noSuchMethod__":
|
||||
raise WebIDLError("__noSuchMethod__ is deprecated", [location])
|
||||
|
||||
if name[:2] == "__" and name != "__content" and not allowDoubleUnderscore:
|
||||
raise WebIDLError("Identifiers beginning with __ are reserved",
|
||||
[location])
|
||||
if name[0] == '_' and not allowDoubleUnderscore:
|
||||
|
@ -448,7 +451,59 @@ class IDLIdentifierPlaceholder(IDLObjectWithIdentifier):
|
|||
obj = self.identifier.resolve(scope, None)
|
||||
return scope.lookupIdentifier(obj)
|
||||
|
||||
class IDLExternalInterface(IDLObjectWithIdentifier):
|
||||
class IDLExposureMixins():
|
||||
def __init__(self, location):
|
||||
# _exposureGlobalNames are the global names listed in our [Exposed]
|
||||
# extended attribute. exposureSet is the exposure set as defined in the
|
||||
# Web IDL spec: it contains interface names.
|
||||
self._exposureGlobalNames = set()
|
||||
self.exposureSet = set()
|
||||
self._location = location
|
||||
self._globalScope = None
|
||||
|
||||
def finish(self, scope):
|
||||
assert scope.parentScope is None
|
||||
self._globalScope = scope
|
||||
|
||||
# Verify that our [Exposed] value, if any, makes sense.
|
||||
for globalName in self._exposureGlobalNames:
|
||||
if globalName not in scope.globalNames:
|
||||
raise WebIDLError("Unknown [Exposed] value %s" % globalName,
|
||||
[self._location])
|
||||
|
||||
if len(self._exposureGlobalNames) == 0:
|
||||
self._exposureGlobalNames.add(scope.primaryGlobalName)
|
||||
|
||||
globalNameSetToExposureSet(scope, self._exposureGlobalNames,
|
||||
self.exposureSet)
|
||||
|
||||
def isExposedInWindow(self):
|
||||
return 'Window' in self.exposureSet
|
||||
|
||||
def isExposedInAnyWorker(self):
|
||||
return len(self.getWorkerExposureSet()) > 0
|
||||
|
||||
def isExposedInSystemGlobals(self):
|
||||
return 'BackstagePass' in self.exposureSet
|
||||
|
||||
def isExposedInSomeButNotAllWorkers(self):
|
||||
"""
|
||||
Returns true if the Exposed extended attribute for this interface
|
||||
exposes it in some worker globals but not others. The return value does
|
||||
not depend on whether the interface is exposed in Window or System
|
||||
globals.
|
||||
"""
|
||||
if not self.isExposedInAnyWorker():
|
||||
return False
|
||||
workerScopes = self.parentScope.globalNameMapping["Worker"]
|
||||
return len(workerScopes.difference(self.exposureSet)) > 0
|
||||
|
||||
def getWorkerExposureSet(self):
|
||||
workerScopes = self._globalScope.globalNameMapping["Worker"]
|
||||
return workerScopes.intersection(self.exposureSet)
|
||||
|
||||
|
||||
class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins):
|
||||
def __init__(self, location, parentScope, identifier):
|
||||
raise WebIDLError("Servo does not support external interfaces.",
|
||||
[self.location])
|
||||
|
@ -511,7 +566,7 @@ def globalNameSetToExposureSet(globalScope, nameSet, exposureSet):
|
|||
for name in nameSet:
|
||||
exposureSet.update(globalScope.globalNameMapping[name])
|
||||
|
||||
class IDLInterface(IDLObjectWithScope):
|
||||
class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
|
||||
def __init__(self, location, parentScope, name, parent, members,
|
||||
isKnownNonPartial):
|
||||
assert isinstance(parentScope, IDLScope)
|
||||
|
@ -546,13 +601,9 @@ class IDLInterface(IDLObjectWithScope):
|
|||
self.totalMembersInSlots = 0
|
||||
# Tracking of the number of own own members we have in slots
|
||||
self._ownMembersInSlots = 0
|
||||
# _exposureGlobalNames are the global names listed in our [Exposed]
|
||||
# extended attribute. exposureSet is the exposure set as defined in the
|
||||
# Web IDL spec: it contains interface names.
|
||||
self._exposureGlobalNames = set()
|
||||
self.exposureSet = set()
|
||||
|
||||
IDLObjectWithScope.__init__(self, location, parentScope, name)
|
||||
IDLExposureMixins.__init__(self, location)
|
||||
|
||||
if isKnownNonPartial:
|
||||
self.setNonPartial(location, parent, members)
|
||||
|
@ -592,17 +643,7 @@ class IDLInterface(IDLObjectWithScope):
|
|||
"declaration" % self.identifier.name,
|
||||
[self.location])
|
||||
|
||||
# Verify that our [Exposed] value, if any, makes sense.
|
||||
for globalName in self._exposureGlobalNames:
|
||||
if globalName not in scope.globalNames:
|
||||
raise WebIDLError("Unknown [Exposed] value %s" % globalName,
|
||||
[self.location])
|
||||
|
||||
if len(self._exposureGlobalNames) == 0:
|
||||
self._exposureGlobalNames.add(scope.primaryGlobalName)
|
||||
|
||||
globalNameSetToExposureSet(scope, self._exposureGlobalNames,
|
||||
self.exposureSet)
|
||||
IDLExposureMixins.finish(self, scope)
|
||||
|
||||
# Now go ahead and merge in our partial interfaces.
|
||||
for partial in self._partialInterfaces:
|
||||
|
@ -681,6 +722,17 @@ class IDLInterface(IDLObjectWithScope):
|
|||
self.parent.identifier.name),
|
||||
[self.location, self.parent.location])
|
||||
|
||||
# Interfaces which have interface objects can't inherit
|
||||
# from [NoInterfaceObject] interfaces.
|
||||
if (self.parent.getExtendedAttribute("NoInterfaceObject") and
|
||||
not self.getExtendedAttribute("NoInterfaceObject")):
|
||||
raise WebIDLError("Interface %s does not have "
|
||||
"[NoInterfaceObject] but inherits from "
|
||||
"interface %s which does" %
|
||||
(self.identifier.name,
|
||||
self.parent.identifier.name),
|
||||
[self.location, self.parent.location])
|
||||
|
||||
for iface in self.implementedInterfaces:
|
||||
iface.finish(scope)
|
||||
|
||||
|
@ -718,9 +770,13 @@ class IDLInterface(IDLObjectWithScope):
|
|||
|
||||
ctor = self.ctor()
|
||||
if ctor is not None:
|
||||
assert len(ctor._exposureGlobalNames) == 0
|
||||
ctor._exposureGlobalNames.update(self._exposureGlobalNames)
|
||||
ctor.finish(scope)
|
||||
|
||||
for ctor in self.namedConstructors:
|
||||
assert len(ctor._exposureGlobalNames) == 0
|
||||
ctor._exposureGlobalNames.update(self._exposureGlobalNames)
|
||||
ctor.finish(scope)
|
||||
|
||||
# Make a copy of our member list, so things that implement us
|
||||
|
@ -921,10 +977,15 @@ class IDLInterface(IDLObjectWithScope):
|
|||
list(i.location for i in
|
||||
self.interfacesBasedOnSelf if i.parent == self))
|
||||
|
||||
|
||||
for member in self.members:
|
||||
member.validate()
|
||||
|
||||
if self.isCallback() and member.getExtendedAttribute("Replaceable"):
|
||||
raise WebIDLError("[Replaceable] used on an attribute on "
|
||||
"interface %s which is a callback interface" %
|
||||
self.identifier.name,
|
||||
[self.location, member.location])
|
||||
|
||||
# Check that PutForwards refers to another attribute and that no
|
||||
# cycles exist in forwarded assignments.
|
||||
if member.isAttr():
|
||||
|
@ -966,10 +1027,25 @@ class IDLInterface(IDLObjectWithScope):
|
|||
|
||||
if (self.getExtendedAttribute("Pref") and
|
||||
self._exposureGlobalNames != set([self.parentScope.primaryGlobalName])):
|
||||
raise WebIDLError("[Pref] used on an member that is not %s-only" %
|
||||
raise WebIDLError("[Pref] used on an interface that is not %s-only" %
|
||||
self.parentScope.primaryGlobalName,
|
||||
[self.location])
|
||||
|
||||
if (self.getExtendedAttribute("CheckPermissions") and
|
||||
self._exposureGlobalNames != set([self.parentScope.primaryGlobalName])):
|
||||
raise WebIDLError("[CheckPermissions] used on an interface that is "
|
||||
"not %s-only" %
|
||||
self.parentScope.primaryGlobalName,
|
||||
[self.location])
|
||||
|
||||
# Conditional exposure makes no sense for interfaces with no
|
||||
# interface object, unless they're navigator properties.
|
||||
if (self.isExposedConditionally() and
|
||||
not self.hasInterfaceObject() and
|
||||
not self.getNavigatorProperty()):
|
||||
raise WebIDLError("Interface with no interface object is "
|
||||
"exposed conditionally",
|
||||
[self.location])
|
||||
|
||||
def isInterface(self):
|
||||
return True
|
||||
|
@ -1151,10 +1227,11 @@ class IDLInterface(IDLObjectWithScope):
|
|||
self.parentScope.globalNames.add(self.identifier.name)
|
||||
self.parentScope.globalNameMapping[self.identifier.name].add(self.identifier.name)
|
||||
self._isOnGlobalProtoChain = True
|
||||
elif (identifier == "NeedNewResolve" or
|
||||
elif (identifier == "NeedResolve" or
|
||||
identifier == "OverrideBuiltins" or
|
||||
identifier == "ChromeOnly" or
|
||||
identifier == "Unforgeable" or
|
||||
identifier == "UnsafeInPrerendering" or
|
||||
identifier == "LegacyEventInit"):
|
||||
# Known extended attributes that do not take values
|
||||
if not attr.noArguments():
|
||||
|
@ -1284,7 +1361,7 @@ class IDLInterface(IDLObjectWithScope):
|
|||
|
||||
def _getDependentObjects(self):
|
||||
deps = set(self.members)
|
||||
deps.union(self.implementedInterfaces)
|
||||
deps.update(self.implementedInterfaces)
|
||||
if self.parent:
|
||||
deps.add(self.parent)
|
||||
return deps
|
||||
|
@ -1292,6 +1369,13 @@ class IDLInterface(IDLObjectWithScope):
|
|||
def hasMembersInSlots(self):
|
||||
return self._ownMembersInSlots != 0
|
||||
|
||||
def isExposedConditionally(self):
|
||||
return (self.getExtendedAttribute("Pref") or
|
||||
self.getExtendedAttribute("ChromeOnly") or
|
||||
self.getExtendedAttribute("Func") or
|
||||
self.getExtendedAttribute("AvailableIn") or
|
||||
self.getExtendedAttribute("CheckPermissions"))
|
||||
|
||||
class IDLDictionary(IDLObjectWithScope):
|
||||
def __init__(self, location, parentScope, name, parent, members):
|
||||
assert isinstance(parentScope, IDLScope)
|
||||
|
@ -1486,7 +1570,7 @@ class IDLType(IDLObject):
|
|||
'any',
|
||||
'domstring',
|
||||
'bytestring',
|
||||
'scalarvaluestring',
|
||||
'usvstring',
|
||||
'object',
|
||||
'date',
|
||||
'void',
|
||||
|
@ -1539,7 +1623,7 @@ class IDLType(IDLObject):
|
|||
def isDOMString(self):
|
||||
return False
|
||||
|
||||
def isScalarValueString(self):
|
||||
def isUSVString(self):
|
||||
return False
|
||||
|
||||
def isVoid(self):
|
||||
|
@ -1688,7 +1772,10 @@ class IDLNullableType(IDLType):
|
|||
assert not innerType.isVoid()
|
||||
assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any]
|
||||
|
||||
IDLType.__init__(self, location, innerType.name)
|
||||
name = innerType.name
|
||||
if innerType.isComplete():
|
||||
name += "OrNull"
|
||||
IDLType.__init__(self, location, name)
|
||||
self.inner = innerType
|
||||
self.builtin = False
|
||||
|
||||
|
@ -1722,8 +1809,8 @@ class IDLNullableType(IDLType):
|
|||
def isDOMString(self):
|
||||
return self.inner.isDOMString()
|
||||
|
||||
def isScalarValueString(self):
|
||||
return self.inner.isScalarValueString()
|
||||
def isUSVString(self):
|
||||
return self.inner.isUSVString()
|
||||
|
||||
def isFloat(self):
|
||||
return self.inner.isFloat()
|
||||
|
@ -1801,7 +1888,7 @@ class IDLNullableType(IDLType):
|
|||
"be a union type that itself has a nullable "
|
||||
"type as a member type", [self.location])
|
||||
|
||||
self.name = self.inner.name
|
||||
self.name = self.inner.name + "OrNull"
|
||||
return self
|
||||
|
||||
def unroll(self):
|
||||
|
@ -1824,6 +1911,10 @@ class IDLSequenceType(IDLType):
|
|||
IDLType.__init__(self, location, parameterType.name)
|
||||
self.inner = parameterType
|
||||
self.builtin = False
|
||||
# Need to set self.name up front if our inner type is already complete,
|
||||
# since in that case our .complete() won't be called.
|
||||
if self.inner.isComplete():
|
||||
self.name = self.inner.name + "Sequence"
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, IDLSequenceType) and self.inner == other.inner
|
||||
|
@ -1846,7 +1937,7 @@ class IDLSequenceType(IDLType):
|
|||
def isDOMString(self):
|
||||
return False
|
||||
|
||||
def isScalarValueString(self):
|
||||
def isUSVString(self):
|
||||
return False
|
||||
|
||||
def isVoid(self):
|
||||
|
@ -1885,7 +1976,7 @@ class IDLSequenceType(IDLType):
|
|||
|
||||
def complete(self, scope):
|
||||
self.inner = self.inner.complete(scope)
|
||||
self.name = self.inner.name
|
||||
self.name = self.inner.name + "Sequence"
|
||||
return self
|
||||
|
||||
def unroll(self):
|
||||
|
@ -1896,7 +1987,8 @@ class IDLSequenceType(IDLType):
|
|||
# Just forward to the union; it'll deal
|
||||
return other.isDistinguishableFrom(self)
|
||||
return (other.isPrimitive() or other.isString() or other.isEnum() or
|
||||
other.isDate() or other.isNonCallbackInterface() or other.isMozMap())
|
||||
other.isDate() or other.isInterface() or other.isDictionary() or
|
||||
other.isCallback() or other.isMozMap())
|
||||
|
||||
def _getDependentObjects(self):
|
||||
return self.inner._getDependentObjects()
|
||||
|
@ -1911,6 +2003,10 @@ class IDLMozMapType(IDLType):
|
|||
IDLType.__init__(self, location, parameterType.name)
|
||||
self.inner = parameterType
|
||||
self.builtin = False
|
||||
# Need to set self.name up front if our inner type is already complete,
|
||||
# since in that case our .complete() won't be called.
|
||||
if self.inner.isComplete():
|
||||
self.name = self.inner.name + "MozMap"
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, IDLMozMapType) and self.inner == other.inner
|
||||
|
@ -1936,7 +2032,7 @@ class IDLMozMapType(IDLType):
|
|||
|
||||
def complete(self, scope):
|
||||
self.inner = self.inner.complete(scope)
|
||||
self.name = self.inner.name
|
||||
self.name = self.inner.name + "MozMap"
|
||||
return self
|
||||
|
||||
def unroll(self):
|
||||
|
@ -1970,6 +2066,10 @@ class IDLUnionType(IDLType):
|
|||
def __eq__(self, other):
|
||||
return isinstance(other, IDLUnionType) and self.memberTypes == other.memberTypes
|
||||
|
||||
def __hash__(self):
|
||||
assert self.isComplete()
|
||||
return self.name.__hash__()
|
||||
|
||||
def isVoid(self):
|
||||
return False
|
||||
|
||||
|
@ -2001,9 +2101,6 @@ class IDLUnionType(IDLType):
|
|||
return typeName(type._identifier.object())
|
||||
if isinstance(type, IDLObjectWithIdentifier):
|
||||
return typeName(type.identifier)
|
||||
if (isinstance(type, IDLType) and
|
||||
(type.isArray() or type.isSequence() or type.isMozMap)):
|
||||
return str(type)
|
||||
return type.name
|
||||
|
||||
for (i, type) in enumerate(self.memberTypes):
|
||||
|
@ -2114,7 +2211,7 @@ class IDLArrayType(IDLType):
|
|||
def isDOMString(self):
|
||||
return False
|
||||
|
||||
def isScalarValueString(self):
|
||||
def isUSVString(self):
|
||||
return False
|
||||
|
||||
def isVoid(self):
|
||||
|
@ -2212,8 +2309,8 @@ class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
|
|||
def isDOMString(self):
|
||||
return self.inner.isDOMString()
|
||||
|
||||
def isScalarValueString(self):
|
||||
return self.inner.isScalarValueString()
|
||||
def isUSVString(self):
|
||||
return self.inner.isUSVString()
|
||||
|
||||
def isVoid(self):
|
||||
return self.inner.isVoid()
|
||||
|
@ -2313,7 +2410,7 @@ class IDLWrapperType(IDLType):
|
|||
def isDOMString(self):
|
||||
return False
|
||||
|
||||
def isScalarValueString(self):
|
||||
def isUSVString(self):
|
||||
return False
|
||||
|
||||
def isVoid(self):
|
||||
|
@ -2387,7 +2484,8 @@ class IDLWrapperType(IDLType):
|
|||
other.isDate())
|
||||
if self.isDictionary() and other.nullable():
|
||||
return False
|
||||
if other.isPrimitive() or other.isString() or other.isEnum() or other.isDate():
|
||||
if (other.isPrimitive() or other.isString() or other.isEnum() or
|
||||
other.isDate() or other.isSequence()):
|
||||
return True
|
||||
if self.isDictionary():
|
||||
return other.isNonCallbackInterface()
|
||||
|
@ -2405,7 +2503,7 @@ class IDLWrapperType(IDLType):
|
|||
(self.isNonCallbackInterface() or
|
||||
other.isNonCallbackInterface()))
|
||||
if (other.isDictionary() or other.isCallback() or
|
||||
other.isSequence() or other.isMozMap() or other.isArray()):
|
||||
other.isMozMap() or other.isArray()):
|
||||
return self.isNonCallbackInterface()
|
||||
|
||||
# Not much else |other| can be
|
||||
|
@ -2441,6 +2539,13 @@ class IDLWrapperType(IDLType):
|
|||
# Bindings.conf, which is still a global dependency.
|
||||
# 2) Changing an interface to a dictionary (or vice versa) with the
|
||||
# same identifier should be incredibly rare.
|
||||
#
|
||||
# On the other hand, if our type is a dictionary, we should
|
||||
# depend on it, because the member types of a dictionary
|
||||
# affect whether a method taking the dictionary as an argument
|
||||
# takes a JSContext* argument or not.
|
||||
if self.isDictionary():
|
||||
return set([self.inner])
|
||||
return set()
|
||||
|
||||
class IDLBuiltinType(IDLType):
|
||||
|
@ -2466,7 +2571,7 @@ class IDLBuiltinType(IDLType):
|
|||
'any',
|
||||
'domstring',
|
||||
'bytestring',
|
||||
'scalarvaluestring',
|
||||
'usvstring',
|
||||
'object',
|
||||
'date',
|
||||
'void',
|
||||
|
@ -2501,7 +2606,7 @@ class IDLBuiltinType(IDLType):
|
|||
Types.any: IDLType.Tags.any,
|
||||
Types.domstring: IDLType.Tags.domstring,
|
||||
Types.bytestring: IDLType.Tags.bytestring,
|
||||
Types.scalarvaluestring: IDLType.Tags.scalarvaluestring,
|
||||
Types.usvstring: IDLType.Tags.usvstring,
|
||||
Types.object: IDLType.Tags.object,
|
||||
Types.date: IDLType.Tags.date,
|
||||
Types.void: IDLType.Tags.void,
|
||||
|
@ -2535,7 +2640,7 @@ class IDLBuiltinType(IDLType):
|
|||
def isString(self):
|
||||
return self._typeTag == IDLBuiltinType.Types.domstring or \
|
||||
self._typeTag == IDLBuiltinType.Types.bytestring or \
|
||||
self._typeTag == IDLBuiltinType.Types.scalarvaluestring
|
||||
self._typeTag == IDLBuiltinType.Types.usvstring
|
||||
|
||||
def isByteString(self):
|
||||
return self._typeTag == IDLBuiltinType.Types.bytestring
|
||||
|
@ -2543,8 +2648,8 @@ class IDLBuiltinType(IDLType):
|
|||
def isDOMString(self):
|
||||
return self._typeTag == IDLBuiltinType.Types.domstring
|
||||
|
||||
def isScalarValueString(self):
|
||||
return self._typeTag == IDLBuiltinType.Types.scalarvaluestring
|
||||
def isUSVString(self):
|
||||
return self._typeTag == IDLBuiltinType.Types.usvstring
|
||||
|
||||
def isInteger(self):
|
||||
return self._typeTag <= IDLBuiltinType.Types.unsigned_long_long
|
||||
|
@ -2698,9 +2803,9 @@ BuiltinTypes = {
|
|||
IDLBuiltinType.Types.bytestring:
|
||||
IDLBuiltinType(BuiltinLocation("<builtin type>"), "ByteString",
|
||||
IDLBuiltinType.Types.bytestring),
|
||||
IDLBuiltinType.Types.scalarvaluestring:
|
||||
IDLBuiltinType(BuiltinLocation("<builtin type>"), "ScalarValueString",
|
||||
IDLBuiltinType.Types.scalarvaluestring),
|
||||
IDLBuiltinType.Types.usvstring:
|
||||
IDLBuiltinType(BuiltinLocation("<builtin type>"), "USVString",
|
||||
IDLBuiltinType.Types.usvstring),
|
||||
IDLBuiltinType.Types.object:
|
||||
IDLBuiltinType(BuiltinLocation("<builtin type>"), "Object",
|
||||
IDLBuiltinType.Types.object),
|
||||
|
@ -2835,10 +2940,10 @@ class IDLValue(IDLObject):
|
|||
raise WebIDLError("Trying to convert unrestricted value %s to non-unrestricted"
|
||||
% self.value, [location]);
|
||||
return self
|
||||
elif self.type.isString() and type.isScalarValueString():
|
||||
# Allow ScalarValueStrings to use default value just like
|
||||
elif self.type.isString() and type.isUSVString():
|
||||
# Allow USVStrings to use default value just like
|
||||
# DOMString. No coercion is required in this case as Codegen.py
|
||||
# treats ScalarValueString just like DOMString, but with an
|
||||
# treats USVString just like DOMString, but with an
|
||||
# extra normalization step.
|
||||
assert self.type.isDOMString()
|
||||
return self
|
||||
|
@ -2923,7 +3028,7 @@ class IDLUndefinedValue(IDLObject):
|
|||
def _getDependentObjects(self):
|
||||
return set()
|
||||
|
||||
class IDLInterfaceMember(IDLObjectWithIdentifier):
|
||||
class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
|
||||
|
||||
Tags = enum(
|
||||
'Const',
|
||||
|
@ -2936,15 +3041,14 @@ class IDLInterfaceMember(IDLObjectWithIdentifier):
|
|||
'Stringifier'
|
||||
)
|
||||
|
||||
AffectsValues = ("Nothing", "Everything")
|
||||
DependsOnValues = ("Nothing", "DOMState", "DeviceState", "Everything")
|
||||
|
||||
def __init__(self, location, identifier, tag):
|
||||
IDLObjectWithIdentifier.__init__(self, location, None, identifier)
|
||||
IDLExposureMixins.__init__(self, location)
|
||||
self.tag = tag
|
||||
self._extendedAttrDict = {}
|
||||
# _exposureGlobalNames are the global names listed in our [Exposed]
|
||||
# extended attribute. exposureSet is the exposure set as defined in the
|
||||
# Web IDL spec: it contains interface names.
|
||||
self._exposureGlobalNames = set()
|
||||
self.exposureSet = set()
|
||||
|
||||
def isMethod(self):
|
||||
return self.tag == IDLInterfaceMember.Tags.Method
|
||||
|
@ -2968,21 +3072,53 @@ class IDLInterfaceMember(IDLObjectWithIdentifier):
|
|||
return self._extendedAttrDict.get(name, None)
|
||||
|
||||
def finish(self, scope):
|
||||
for globalName in self._exposureGlobalNames:
|
||||
if globalName not in scope.globalNames:
|
||||
raise WebIDLError("Unknown [Exposed] value %s" % globalName,
|
||||
[self.location])
|
||||
globalNameSetToExposureSet(scope, self._exposureGlobalNames,
|
||||
self.exposureSet)
|
||||
self._scope = scope
|
||||
# We better be exposed _somewhere_.
|
||||
if (len(self._exposureGlobalNames) == 0):
|
||||
print self.identifier.name
|
||||
assert len(self._exposureGlobalNames) != 0
|
||||
IDLExposureMixins.finish(self, scope)
|
||||
|
||||
def validate(self):
|
||||
if (self.getExtendedAttribute("Pref") and
|
||||
self.exposureSet != set([self._scope.primaryGlobalName])):
|
||||
self.exposureSet != set([self._globalScope.primaryGlobalName])):
|
||||
raise WebIDLError("[Pref] used on an interface member that is not "
|
||||
"%s-only" % self._scope.primaryGlobalName,
|
||||
"%s-only" % self._globalScope.primaryGlobalName,
|
||||
[self.location])
|
||||
|
||||
if (self.getExtendedAttribute("CheckPermissions") and
|
||||
self.exposureSet != set([self._globalScope.primaryGlobalName])):
|
||||
raise WebIDLError("[CheckPermissions] used on an interface member "
|
||||
"that is not %s-only" %
|
||||
self._globalScope.primaryGlobalName,
|
||||
[self.location])
|
||||
|
||||
if self.isAttr() or self.isMethod():
|
||||
if self.affects == "Everything" and self.dependsOn != "Everything":
|
||||
raise WebIDLError("Interface member is flagged as affecting "
|
||||
"everything but not depending on everything. "
|
||||
"That seems rather unlikely.",
|
||||
[self.location])
|
||||
|
||||
def _setDependsOn(self, dependsOn):
|
||||
if self.dependsOn != "Everything":
|
||||
raise WebIDLError("Trying to specify multiple different DependsOn, "
|
||||
"Pure, or Constant extended attributes for "
|
||||
"attribute", [self.location])
|
||||
if dependsOn not in IDLInterfaceMember.DependsOnValues:
|
||||
raise WebIDLError("Invalid [DependsOn=%s] on attribute" % dependsOn,
|
||||
[self.location])
|
||||
self.dependsOn = dependsOn
|
||||
|
||||
def _setAffects(self, affects):
|
||||
if self.affects != "Everything":
|
||||
raise WebIDLError("Trying to specify multiple different Affects, "
|
||||
"Pure, or Constant extended attributes for "
|
||||
"attribute", [self.location])
|
||||
if affects not in IDLInterfaceMember.AffectsValues:
|
||||
raise WebIDLError("Invalid [Affects=%s] on attribute" % dependsOn,
|
||||
[self.location])
|
||||
self.affects = affects
|
||||
|
||||
class IDLConst(IDLInterfaceMember):
|
||||
def __init__(self, location, identifier, type, value):
|
||||
IDLInterfaceMember.__init__(self, location, identifier,
|
||||
|
@ -3061,6 +3197,8 @@ class IDLAttribute(IDLInterfaceMember):
|
|||
self.enforceRange = False
|
||||
self.clamp = False
|
||||
self.slotIndex = None
|
||||
self.dependsOn = "Everything"
|
||||
self.affects = "Everything"
|
||||
|
||||
if static and identifier.name == "prototype":
|
||||
raise WebIDLError("The identifier of a static attribute must not be 'prototype'",
|
||||
|
@ -3129,11 +3267,11 @@ class IDLAttribute(IDLInterfaceMember):
|
|||
|
||||
if ((self.getExtendedAttribute("Cached") or
|
||||
self.getExtendedAttribute("StoreInSlot")) and
|
||||
not self.getExtendedAttribute("Constant") and
|
||||
not self.getExtendedAttribute("Pure")):
|
||||
not self.affects == "Nothing"):
|
||||
raise WebIDLError("Cached attributes and attributes stored in "
|
||||
"slots must be constant or pure, since the "
|
||||
"getter won't always be called.",
|
||||
"slots must be Constant or Pure or "
|
||||
"Affects=Nothing, since the getter won't always "
|
||||
"be called.",
|
||||
[self.location])
|
||||
if self.getExtendedAttribute("Frozen"):
|
||||
if (not self.type.isSequence() and not self.type.isDictionary() and
|
||||
|
@ -3158,8 +3296,7 @@ class IDLAttribute(IDLInterfaceMember):
|
|||
(identifier == "StoreInSlot" and
|
||||
(self.getExtendedAttribute("Throws") or
|
||||
self.getExtendedAttribute("GetterThrows")))):
|
||||
raise WebIDLError("Throwing things can't be [Pure] or [Constant] "
|
||||
"or [SameObject] or [StoreInSlot]",
|
||||
raise WebIDLError("Throwing things can't be [StoreInSlot]",
|
||||
[attr.location])
|
||||
elif identifier == "LenientThis":
|
||||
if not attr.noArguments():
|
||||
|
@ -3203,6 +3340,15 @@ class IDLAttribute(IDLInterfaceMember):
|
|||
raise WebIDLError("[PutForwards] takes an identifier",
|
||||
[attr.location, self.location])
|
||||
elif identifier == "Replaceable":
|
||||
if not attr.noArguments():
|
||||
raise WebIDLError("[Replaceable] must take no arguments",
|
||||
[attr.location])
|
||||
if not self.readonly:
|
||||
raise WebIDLError("[Replaceable] is only allowed on readonly "
|
||||
"attributes", [attr.location, self.location])
|
||||
if self.isStatic():
|
||||
raise WebIDLError("[Replaceable] is only allowed on non-static "
|
||||
"attributes", [attr.location, self.location])
|
||||
if self.getExtendedAttribute("PutForwards") is not None:
|
||||
raise WebIDLError("[PutForwards] and [Replaceable] can't both "
|
||||
"appear on the same attribute",
|
||||
|
@ -3250,18 +3396,43 @@ class IDLAttribute(IDLInterfaceMember):
|
|||
[attr.location, self.location])
|
||||
elif identifier == "Exposed":
|
||||
convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
|
||||
elif identifier == "Pure":
|
||||
if not attr.noArguments():
|
||||
raise WebIDLError("[Pure] must take no arguments",
|
||||
[attr.location])
|
||||
self._setDependsOn("DOMState")
|
||||
self._setAffects("Nothing")
|
||||
elif identifier == "Constant" or identifier == "SameObject":
|
||||
if not attr.noArguments():
|
||||
raise WebIDLError("[%s] must take no arguments" % identifier,
|
||||
[attr.location])
|
||||
self._setDependsOn("Nothing")
|
||||
self._setAffects("Nothing")
|
||||
elif identifier == "Affects":
|
||||
if not attr.hasValue():
|
||||
raise WebIDLError("[Affects] takes an identifier",
|
||||
[attr.location])
|
||||
self._setAffects(attr.value())
|
||||
elif identifier == "DependsOn":
|
||||
if not attr.hasValue():
|
||||
raise WebIDLError("[DependsOn] takes an identifier",
|
||||
[attr.location])
|
||||
if (attr.value() != "Everything" and attr.value() != "DOMState" and
|
||||
not self.readonly):
|
||||
raise WebIDLError("[DependsOn=%s] only allowed on "
|
||||
"readonly attributes" % attr.value(),
|
||||
[attr.location, self.location])
|
||||
self._setDependsOn(attr.value())
|
||||
elif (identifier == "Pref" or
|
||||
identifier == "SetterThrows" or
|
||||
identifier == "Pure" or
|
||||
identifier == "Throws" or
|
||||
identifier == "GetterThrows" or
|
||||
identifier == "ChromeOnly" or
|
||||
identifier == "SameObject" or
|
||||
identifier == "Constant" or
|
||||
identifier == "Func" or
|
||||
identifier == "Frozen" or
|
||||
identifier == "AvailableIn" or
|
||||
identifier == "NewObject" or
|
||||
identifier == "UnsafeInPrerendering" or
|
||||
identifier == "CheckPermissions" or
|
||||
identifier == "BinaryName"):
|
||||
# Known attributes that we don't need to do anything with here
|
||||
|
@ -3306,6 +3477,7 @@ class IDLArgument(IDLObjectWithIdentifier):
|
|||
self._allowTreatNonCallableAsNull = False
|
||||
|
||||
assert not variadic or optional
|
||||
assert not variadic or not defaultValue
|
||||
|
||||
def addExtendedAttributes(self, attrs):
|
||||
attrs = self.checkForStringHandlingExtendedAttributes(
|
||||
|
@ -3354,9 +3526,9 @@ class IDLArgument(IDLObjectWithIdentifier):
|
|||
|
||||
if ((self.type.isDictionary() or
|
||||
self.type.isUnion() and self.type.unroll().hasDictionaryType) and
|
||||
self.optional and not self.defaultValue):
|
||||
# Default optional dictionaries to null, for simplicity,
|
||||
# so the codegen doesn't have to special-case this.
|
||||
self.optional and not self.defaultValue and not self.variadic):
|
||||
# Default optional non-variadic dictionaries to null,
|
||||
# for simplicity, so the codegen doesn't have to special-case this.
|
||||
self.defaultValue = IDLNullValue(self.location)
|
||||
elif self.type.isAny():
|
||||
assert (self.defaultValue is None or
|
||||
|
@ -3383,6 +3555,9 @@ class IDLArgument(IDLObjectWithIdentifier):
|
|||
deps.add(self.defaultValue)
|
||||
return deps
|
||||
|
||||
def canHaveMissingValue(self):
|
||||
return self.optional and not self.defaultValue
|
||||
|
||||
class IDLCallbackType(IDLType, IDLObjectWithScope):
|
||||
def __init__(self, location, parentScope, identifier, returnType, arguments):
|
||||
assert isinstance(returnType, IDLType)
|
||||
|
@ -3442,7 +3617,8 @@ class IDLCallbackType(IDLType, IDLObjectWithScope):
|
|||
# Just forward to the union; it'll deal
|
||||
return other.isDistinguishableFrom(self)
|
||||
return (other.isPrimitive() or other.isString() or other.isEnum() or
|
||||
other.isNonCallbackInterface() or other.isDate())
|
||||
other.isNonCallbackInterface() or other.isDate() or
|
||||
other.isSequence())
|
||||
|
||||
def addExtendedAttributes(self, attrs):
|
||||
unhandledAttrs = []
|
||||
|
@ -3538,6 +3714,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
self._jsonifier = jsonifier
|
||||
self._specialType = specialType
|
||||
self._unforgeable = False
|
||||
self.dependsOn = "Everything"
|
||||
self.affects = "Everything"
|
||||
|
||||
if static and identifier.name == "prototype":
|
||||
raise WebIDLError("The identifier of a static operation must not be 'prototype'",
|
||||
|
@ -3618,7 +3796,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
return self._hasOverloads
|
||||
|
||||
def isIdentifierLess(self):
|
||||
return self.identifier.name[:2] == "__" and self.identifier.name != "__noSuchMethod__"
|
||||
return self.identifier.name[:2] == "__"
|
||||
|
||||
def resolve(self, parentScope):
|
||||
assert isinstance(parentScope, IDLScope)
|
||||
|
@ -3849,16 +4027,32 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
[attr.location, self.location])
|
||||
elif identifier == "Exposed":
|
||||
convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames)
|
||||
elif (identifier == "Pure" or
|
||||
identifier == "CrossOriginCallable" or
|
||||
elif (identifier == "CrossOriginCallable" or
|
||||
identifier == "WebGLHandlesContextLoss"):
|
||||
# Known no-argument attributes.
|
||||
if not attr.noArguments():
|
||||
raise WebIDLError("[%s] must take no arguments" % identifier,
|
||||
[attr.location])
|
||||
elif identifier == "Pure":
|
||||
if not attr.noArguments():
|
||||
raise WebIDLError("[Pure] must take no arguments",
|
||||
[attr.location])
|
||||
self._setDependsOn("DOMState")
|
||||
self._setAffects("Nothing")
|
||||
elif identifier == "Affects":
|
||||
if not attr.hasValue():
|
||||
raise WebIDLError("[Affects] takes an identifier",
|
||||
[attr.location])
|
||||
self._setAffects(attr.value())
|
||||
elif identifier == "DependsOn":
|
||||
if not attr.hasValue():
|
||||
raise WebIDLError("[DependsOn] takes an identifier",
|
||||
[attr.location])
|
||||
self._setDependsOn(attr.value())
|
||||
elif (identifier == "Throws" or
|
||||
identifier == "NewObject" or
|
||||
identifier == "ChromeOnly" or
|
||||
identifier == "UnsafeInPrerendering" or
|
||||
identifier == "Pref" or
|
||||
identifier == "Func" or
|
||||
identifier == "AvailableIn" or
|
||||
|
@ -3880,7 +4074,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
def _getDependentObjects(self):
|
||||
deps = set()
|
||||
for overload in self._overloads:
|
||||
deps.union(overload._getDependentObjects())
|
||||
deps.update(overload._getDependentObjects())
|
||||
return deps
|
||||
|
||||
class IDLImplementsStatement(IDLObject):
|
||||
|
@ -3888,8 +4082,11 @@ class IDLImplementsStatement(IDLObject):
|
|||
IDLObject.__init__(self, location)
|
||||
self.implementor = implementor;
|
||||
self.implementee = implementee
|
||||
self._finished = False
|
||||
|
||||
def finish(self, scope):
|
||||
if self._finished:
|
||||
return
|
||||
assert(isinstance(self.implementor, IDLIdentifierPlaceholder))
|
||||
assert(isinstance(self.implementee, IDLIdentifierPlaceholder))
|
||||
implementor = self.implementor.finish(scope)
|
||||
|
@ -3914,6 +4111,8 @@ class IDLImplementsStatement(IDLObject):
|
|||
"interface",
|
||||
[self.implementee.location])
|
||||
implementor.addImplementedInterface(implementee)
|
||||
self.implementor = implementor
|
||||
self.implementee = implementee
|
||||
|
||||
def validate(self):
|
||||
pass
|
||||
|
@ -4044,7 +4243,7 @@ class Tokenizer(object):
|
|||
"Date": "DATE",
|
||||
"DOMString": "DOMSTRING",
|
||||
"ByteString": "BYTESTRING",
|
||||
"ScalarValueString": "SCALARVALUESTRING",
|
||||
"USVString": "USVSTRING",
|
||||
"any": "ANY",
|
||||
"boolean": "BOOLEAN",
|
||||
"byte": "BYTE",
|
||||
|
@ -4053,8 +4252,8 @@ class Tokenizer(object):
|
|||
"long": "LONG",
|
||||
"object": "OBJECT",
|
||||
"octet": "OCTET",
|
||||
"optional": "OPTIONAL",
|
||||
"Promise": "PROMISE",
|
||||
"required": "REQUIRED",
|
||||
"sequence": "SEQUENCE",
|
||||
"MozMap": "MOZMAP",
|
||||
"short": "SHORT",
|
||||
|
@ -4339,15 +4538,21 @@ class Parser(Tokenizer):
|
|||
|
||||
def p_DictionaryMember(self, p):
|
||||
"""
|
||||
DictionaryMember : Type IDENTIFIER Default SEMICOLON
|
||||
DictionaryMember : Required Type IDENTIFIER Default SEMICOLON
|
||||
"""
|
||||
# These quack a lot like optional arguments, so just treat them that way.
|
||||
t = p[1]
|
||||
t = p[2]
|
||||
assert isinstance(t, IDLType)
|
||||
identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
|
||||
defaultValue = p[3]
|
||||
identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3])
|
||||
defaultValue = p[4]
|
||||
optional = not p[1]
|
||||
|
||||
p[0] = IDLArgument(self.getLocation(p, 2), identifier, t, optional=True,
|
||||
if not optional and defaultValue:
|
||||
raise WebIDLError("Required dictionary members can't have a default value.",
|
||||
[self.getLocation(p, 4)])
|
||||
|
||||
p[0] = IDLArgument(self.getLocation(p, 3), identifier, t,
|
||||
optional=optional,
|
||||
defaultValue=defaultValue, variadic=False,
|
||||
dictionaryMember=True)
|
||||
|
||||
|
@ -4545,7 +4750,7 @@ class Parser(Tokenizer):
|
|||
|
||||
def p_AttributeRest(self, p):
|
||||
"""
|
||||
AttributeRest : ReadOnly ATTRIBUTE Type IDENTIFIER SEMICOLON
|
||||
AttributeRest : ReadOnly ATTRIBUTE Type AttributeName SEMICOLON
|
||||
"""
|
||||
location = self.getLocation(p, 2)
|
||||
readonly = p[1]
|
||||
|
@ -4874,6 +5079,7 @@ class Parser(Tokenizer):
|
|||
| INTERFACE
|
||||
| LEGACYCALLER
|
||||
| PARTIAL
|
||||
| REQUIRED
|
||||
| SERIALIZER
|
||||
| SETTER
|
||||
| STATIC
|
||||
|
@ -4884,6 +5090,13 @@ class Parser(Tokenizer):
|
|||
"""
|
||||
p[0] = p[1]
|
||||
|
||||
def p_AttributeName(self, p):
|
||||
"""
|
||||
AttributeName : IDENTIFIER
|
||||
| REQUIRED
|
||||
"""
|
||||
p[0] = p[1]
|
||||
|
||||
def p_Optional(self, p):
|
||||
"""
|
||||
Optional : OPTIONAL
|
||||
|
@ -4896,6 +5109,18 @@ class Parser(Tokenizer):
|
|||
"""
|
||||
p[0] = False
|
||||
|
||||
def p_Required(self, p):
|
||||
"""
|
||||
Required : REQUIRED
|
||||
"""
|
||||
p[0] = True
|
||||
|
||||
def p_RequiredEmpty(self, p):
|
||||
"""
|
||||
Required :
|
||||
"""
|
||||
p[0] = False
|
||||
|
||||
def p_Ellipsis(self, p):
|
||||
"""
|
||||
Ellipsis : ELLIPSIS
|
||||
|
@ -4982,7 +5207,7 @@ class Parser(Tokenizer):
|
|||
| DATE
|
||||
| DOMSTRING
|
||||
| BYTESTRING
|
||||
| SCALARVALUESTRING
|
||||
| USVSTRING
|
||||
| ANY
|
||||
| ATTRIBUTE
|
||||
| BOOLEAN
|
||||
|
@ -5255,11 +5480,11 @@ class Parser(Tokenizer):
|
|||
"""
|
||||
p[0] = IDLBuiltinType.Types.bytestring
|
||||
|
||||
def p_PrimitiveOrStringTypeScalarValueString(self, p):
|
||||
def p_PrimitiveOrStringTypeUSVString(self, p):
|
||||
"""
|
||||
PrimitiveOrStringType : SCALARVALUESTRING
|
||||
PrimitiveOrStringType : USVSTRING
|
||||
"""
|
||||
p[0] = IDLBuiltinType.Types.scalarvaluestring
|
||||
p[0] = IDLBuiltinType.Types.usvstring
|
||||
|
||||
def p_UnsignedIntegerTypeUnsigned(self, p):
|
||||
"""
|
||||
|
@ -5473,6 +5698,10 @@ class Parser(Tokenizer):
|
|||
self._globalScope.primaryGlobalName = "FakeTestPrimaryGlobal"
|
||||
self._globalScope.globalNames.add("FakeTestPrimaryGlobal")
|
||||
self._globalScope.globalNameMapping["FakeTestPrimaryGlobal"].add("FakeTestPrimaryGlobal")
|
||||
# And we add the special-cased "System" global name, which
|
||||
# doesn't have any corresponding interfaces.
|
||||
self._globalScope.globalNames.add("System")
|
||||
self._globalScope.globalNameMapping["System"].add("BackstagePass")
|
||||
self._installBuiltins(self._globalScope)
|
||||
self._productions = []
|
||||
|
||||
|
@ -5548,6 +5777,7 @@ class Parser(Tokenizer):
|
|||
# Builtin IDL defined by WebIDL
|
||||
_builtins = """
|
||||
typedef unsigned long long DOMTimeStamp;
|
||||
typedef (ArrayBufferView or ArrayBuffer) BufferSource;
|
||||
"""
|
||||
|
||||
def main():
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue