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
866a523914
commit
938f1362e7
12 changed files with 104 additions and 244 deletions
|
@ -1095,12 +1095,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
testInterface = testInterface.parent
|
||||
|
||||
# Ensure that there's at most one of each {named,indexed}
|
||||
# {getter,setter,creator,deleter}, at most one stringifier,
|
||||
# {getter,setter,deleter}, at most one stringifier,
|
||||
# and at most one legacycaller. Note that this last is not
|
||||
# quite per spec, but in practice no one overloads
|
||||
# legacycallers. Also note that in practice we disallow
|
||||
# indexed deleters, but it simplifies some other code to
|
||||
# treat deleter analogously to getter/setter/creator by
|
||||
# treat deleter analogously to getter/setter by
|
||||
# prefixing it with "named".
|
||||
specialMembersSeen = {}
|
||||
for member in self.members:
|
||||
|
@ -1111,8 +1111,6 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
memberType = "getters"
|
||||
elif member.isSetter():
|
||||
memberType = "setters"
|
||||
elif member.isCreator():
|
||||
memberType = "creators"
|
||||
elif member.isDeleter():
|
||||
memberType = "deleters"
|
||||
elif member.isStringifier():
|
||||
|
@ -1158,8 +1156,8 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
ancestor = ancestor.parent
|
||||
|
||||
if self._isOnGlobalProtoChain:
|
||||
# Make sure we have no named setters, creators, or deleters
|
||||
for memberType in ["setter", "creator", "deleter"]:
|
||||
# Make sure we have no named setters or deleters
|
||||
for memberType in ["setter", "deleter"]:
|
||||
memberId = "named " + memberType + "s"
|
||||
if memberId in specialMembersSeen:
|
||||
raise WebIDLError("Interface with [Global] has a named %s" %
|
||||
|
@ -1183,6 +1181,22 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
parent = parent.parent
|
||||
|
||||
def validate(self):
|
||||
|
||||
def checkDuplicateNames(member, name, attributeName):
|
||||
for m in self.members:
|
||||
if m.identifier.name == name:
|
||||
raise WebIDLError("[%s=%s] has same name as interface member" %
|
||||
(attributeName, name),
|
||||
[member.location, m.location])
|
||||
if m.isMethod() and m != member and name in m.aliases:
|
||||
raise WebIDLError("conflicting [%s=%s] definitions" %
|
||||
(attributeName, name),
|
||||
[member.location, m.location])
|
||||
if m.isAttr() and m != member and name in m.bindingAliases:
|
||||
raise WebIDLError("conflicting [%s=%s] definitions" %
|
||||
(attributeName, name),
|
||||
[member.location, m.location])
|
||||
|
||||
# We don't support consequential unforgeable interfaces. Need to check
|
||||
# this here, because in finish() an interface might not know yet that
|
||||
# it's consequential.
|
||||
|
@ -1295,15 +1309,15 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
raise WebIDLError("[Alias] must not be used on an "
|
||||
"[Unforgeable] operation",
|
||||
[member.location])
|
||||
for m in self.members:
|
||||
if m.identifier.name == alias:
|
||||
raise WebIDLError("[Alias=%s] has same name as "
|
||||
"interface member" % alias,
|
||||
[member.location, m.location])
|
||||
if m.isMethod() and m != member and alias in m.aliases:
|
||||
raise WebIDLError("duplicate [Alias=%s] definitions" %
|
||||
alias,
|
||||
[member.location, m.location])
|
||||
|
||||
checkDuplicateNames(member, alias, "Alias")
|
||||
|
||||
# Check that the name of a [BindingAlias] doesn't conflict with an
|
||||
# interface member.
|
||||
if member.isAttr():
|
||||
for bindingAlias in member.bindingAliases:
|
||||
checkDuplicateNames(member, bindingAlias, "BindingAlias")
|
||||
|
||||
|
||||
# Conditional exposure makes no sense for interfaces with no
|
||||
# interface object, unless they're navigator properties.
|
||||
|
@ -1720,10 +1734,10 @@ class IDLInterface(IDLInterfaceOrNamespace):
|
|||
identifier == "OverrideBuiltins" or
|
||||
identifier == "ChromeOnly" or
|
||||
identifier == "Unforgeable" or
|
||||
identifier == "UnsafeInPrerendering" or
|
||||
identifier == "LegacyEventInit" or
|
||||
identifier == "ProbablyShortLivingWrapper" or
|
||||
identifier == "LegacyUnenumerableNamedProperties" or
|
||||
identifier == "RunConstructorInCallerCompartment" or
|
||||
identifier == "NonOrdinaryGetPrototypeOf" or
|
||||
identifier == "Abstract" or
|
||||
identifier == "Inline"):
|
||||
|
@ -1780,10 +1794,16 @@ class IDLNamespace(IDLInterfaceOrNamespace):
|
|||
if not attr.hasValue():
|
||||
raise WebIDLError("[%s] must have a value" % identifier,
|
||||
[attr.location])
|
||||
elif identifier == "ProtoObjectHack":
|
||||
elif (identifier == "ProtoObjectHack" or
|
||||
identifier == "ChromeOnly"):
|
||||
if not attr.noArguments():
|
||||
raise WebIDLError("[%s] must not have arguments" % identifier,
|
||||
[attr.location])
|
||||
elif identifier == "Pref":
|
||||
# Known extended attributes that take a string value
|
||||
if not attr.hasValue():
|
||||
raise WebIDLError("[%s] must have a value" % identifier,
|
||||
[attr.location])
|
||||
else:
|
||||
raise WebIDLError("Unknown extended attribute %s on namespace" %
|
||||
identifier,
|
||||
|
@ -3581,6 +3601,11 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
|
|||
[self.location])
|
||||
self.aliases.append(alias)
|
||||
|
||||
def _addBindingAlias(self, bindingAlias):
|
||||
if bindingAlias in self.bindingAliases:
|
||||
raise WebIDLError("Duplicate [BindingAlias=%s] on attribute" % bindingAlias,
|
||||
[self.location])
|
||||
self.bindingAliases.append(bindingAlias)
|
||||
|
||||
class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember):
|
||||
|
||||
|
@ -3701,6 +3726,11 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember):
|
|||
if isIteratorAlias:
|
||||
method.addExtendedAttributes(
|
||||
[IDLExtendedAttribute(self.location, ("Alias", "@@iterator"))])
|
||||
# Methods generated for iterables should be enumerable, but the ones for
|
||||
# maplike/setlike should not be.
|
||||
if not self.isIterable():
|
||||
method.addExtendedAttributes(
|
||||
[IDLExtendedAttribute(self.location, ("NonEnumerable",))])
|
||||
members.append(method)
|
||||
|
||||
def resolve(self, parentScope):
|
||||
|
@ -3824,11 +3854,15 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase):
|
|||
specification during parsing.
|
||||
"""
|
||||
# Both maplike and setlike have a size attribute
|
||||
members.append(IDLAttribute(self.location,
|
||||
IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), "size"),
|
||||
BuiltinTypes[IDLBuiltinType.Types.unsigned_long],
|
||||
True,
|
||||
maplikeOrSetlike=self))
|
||||
sizeAttr = IDLAttribute(self.location,
|
||||
IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), "size"),
|
||||
BuiltinTypes[IDLBuiltinType.Types.unsigned_long],
|
||||
True,
|
||||
maplikeOrSetlike=self)
|
||||
# This should be non-enumerable.
|
||||
sizeAttr.addExtendedAttributes(
|
||||
[IDLExtendedAttribute(self.location, ("NonEnumerable",))])
|
||||
members.append(sizeAttr)
|
||||
self.reserved_ro_names = ["size"]
|
||||
self.disallowedMemberNames.append("size")
|
||||
|
||||
|
@ -3964,7 +3998,9 @@ class IDLConst(IDLInterfaceMember):
|
|||
elif (identifier == "Pref" or
|
||||
identifier == "ChromeOnly" or
|
||||
identifier == "Func" or
|
||||
identifier == "SecureContext"):
|
||||
identifier == "SecureContext" or
|
||||
identifier == "NonEnumerable" or
|
||||
identifier == "NeedsWindowsUndef"):
|
||||
# Known attributes that we don't need to do anything with here
|
||||
pass
|
||||
else:
|
||||
|
@ -4000,6 +4036,7 @@ class IDLAttribute(IDLInterfaceMember):
|
|||
self.dependsOn = "Everything"
|
||||
self.affects = "Everything"
|
||||
self.navigatorObjectGetter = navigatorObjectGetter
|
||||
self.bindingAliases = []
|
||||
|
||||
if static and identifier.name == "prototype":
|
||||
raise WebIDLError("The identifier of a static attribute must not be 'prototype'",
|
||||
|
@ -4138,11 +4175,17 @@ class IDLAttribute(IDLInterfaceMember):
|
|||
|
||||
def handleExtendedAttribute(self, attr):
|
||||
identifier = attr.identifier()
|
||||
if ((identifier == "SetterThrows" or identifier == "SetterCanOOM")
|
||||
if ((identifier == "SetterThrows" or identifier == "SetterCanOOM" or
|
||||
identifier == "SetterNeedsSubjectPrincipal")
|
||||
and self.readonly):
|
||||
raise WebIDLError("Readonly attributes must not be flagged as "
|
||||
"[%s]" % identifier,
|
||||
[self.location])
|
||||
elif identifier == "BindingAlias":
|
||||
if not attr.hasValue():
|
||||
raise WebIDLError("[BindingAlias] takes an identifier or string",
|
||||
[attr.location])
|
||||
self._addBindingAlias(attr.value())
|
||||
elif (((identifier == "Throws" or identifier == "GetterThrows" or
|
||||
identifier == "CanOOM" or identifier == "GetterCanOOM") and
|
||||
self.getExtendedAttribute("StoreInSlot")) or
|
||||
|
@ -4338,11 +4381,13 @@ class IDLAttribute(IDLInterfaceMember):
|
|||
identifier == "SecureContext" or
|
||||
identifier == "Frozen" or
|
||||
identifier == "NewObject" or
|
||||
identifier == "UnsafeInPrerendering" or
|
||||
identifier == "NeedsSubjectPrincipal" or
|
||||
identifier == "SetterNeedsSubjectPrincipal" or
|
||||
identifier == "GetterNeedsSubjectPrincipal" or
|
||||
identifier == "NeedsCallerType" or
|
||||
identifier == "ReturnValueNeedsContainsHack" or
|
||||
identifier == "BinaryName"):
|
||||
identifier == "BinaryName" or
|
||||
identifier == "NonEnumerable"):
|
||||
# Known attributes that we don't need to do anything with here
|
||||
pass
|
||||
else:
|
||||
|
@ -4606,7 +4651,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
Special = enum(
|
||||
'Getter',
|
||||
'Setter',
|
||||
'Creator',
|
||||
'Deleter',
|
||||
'LegacyCaller',
|
||||
base=IDLInterfaceMember.Special
|
||||
|
@ -4619,7 +4663,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
)
|
||||
|
||||
def __init__(self, location, identifier, returnType, arguments,
|
||||
static=False, getter=False, setter=False, creator=False,
|
||||
static=False, getter=False, setter=False,
|
||||
deleter=False, specialType=NamedOrIndexed.Neither,
|
||||
legacycaller=False, stringifier=False, jsonifier=False,
|
||||
maplikeOrSetlikeOrIterable=None, htmlConstructor=False):
|
||||
|
@ -4640,8 +4684,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
self._getter = getter
|
||||
assert isinstance(setter, bool)
|
||||
self._setter = setter
|
||||
assert isinstance(creator, bool)
|
||||
self._creator = creator
|
||||
assert isinstance(deleter, bool)
|
||||
self._deleter = deleter
|
||||
assert isinstance(legacycaller, bool)
|
||||
|
@ -4682,7 +4724,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
assert not arguments[0].optional and not arguments[0].variadic
|
||||
assert not self._getter or not overload.returnType.isVoid()
|
||||
|
||||
if self._setter or self._creator:
|
||||
if self._setter:
|
||||
assert len(self._overloads) == 1
|
||||
arguments = self._overloads[0].arguments
|
||||
assert len(arguments) == 2
|
||||
|
@ -4715,9 +4757,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
def isSetter(self):
|
||||
return self._setter
|
||||
|
||||
def isCreator(self):
|
||||
return self._creator
|
||||
|
||||
def isDeleter(self):
|
||||
return self._deleter
|
||||
|
||||
|
@ -4750,7 +4789,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
def isSpecial(self):
|
||||
return (self.isGetter() or
|
||||
self.isSetter() or
|
||||
self.isCreator() or
|
||||
self.isDeleter() or
|
||||
self.isLegacycaller() or
|
||||
self.isStringifier() or
|
||||
|
@ -4806,8 +4844,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
assert not method.isGetter()
|
||||
assert not self.isSetter()
|
||||
assert not method.isSetter()
|
||||
assert not self.isCreator()
|
||||
assert not method.isCreator()
|
||||
assert not self.isDeleter()
|
||||
assert not method.isDeleter()
|
||||
assert not self.isStringifier()
|
||||
|
@ -4984,7 +5020,9 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
if (identifier == "GetterThrows" or
|
||||
identifier == "SetterThrows" or
|
||||
identifier == "GetterCanOOM" or
|
||||
identifier == "SetterCanOOM"):
|
||||
identifier == "SetterCanOOM" or
|
||||
identifier == "SetterNeedsSubjectPrincipal" or
|
||||
identifier == "GetterNeedsSubjectPrincipal"):
|
||||
raise WebIDLError("Methods must not be flagged as "
|
||||
"[%s]" % identifier,
|
||||
[attr.location, self.location])
|
||||
|
@ -5071,7 +5109,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
identifier == "CanOOM" or
|
||||
identifier == "NewObject" or
|
||||
identifier == "ChromeOnly" or
|
||||
identifier == "UnsafeInPrerendering" or
|
||||
identifier == "Pref" or
|
||||
identifier == "Deprecated" or
|
||||
identifier == "Func" or
|
||||
|
@ -5079,7 +5116,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
identifier == "BinaryName" or
|
||||
identifier == "NeedsSubjectPrincipal" or
|
||||
identifier == "NeedsCallerType" or
|
||||
identifier == "StaticClassOverride"):
|
||||
identifier == "StaticClassOverride" or
|
||||
identifier == "NonEnumerable"):
|
||||
# Known attributes that we don't need to do anything with here
|
||||
pass
|
||||
else:
|
||||
|
@ -5262,7 +5300,6 @@ class Tokenizer(object):
|
|||
"static": "STATIC",
|
||||
"getter": "GETTER",
|
||||
"setter": "SETTER",
|
||||
"creator": "CREATOR",
|
||||
"deleter": "DELETER",
|
||||
"legacycaller": "LEGACYCALLER",
|
||||
"optional": "OPTIONAL",
|
||||
|
@ -5977,13 +6014,12 @@ class Parser(Tokenizer):
|
|||
|
||||
getter = True if IDLMethod.Special.Getter in p[1] else False
|
||||
setter = True if IDLMethod.Special.Setter in p[1] else False
|
||||
creator = True if IDLMethod.Special.Creator in p[1] else False
|
||||
deleter = True if IDLMethod.Special.Deleter in p[1] else False
|
||||
legacycaller = True if IDLMethod.Special.LegacyCaller in p[1] else False
|
||||
|
||||
if getter or deleter:
|
||||
if setter or creator:
|
||||
raise WebIDLError("getter and deleter are incompatible with setter and creator",
|
||||
if setter:
|
||||
raise WebIDLError("getter and deleter are incompatible with setter",
|
||||
[self.getLocation(p, 1)])
|
||||
|
||||
(returnType, identifier, arguments) = p[2]
|
||||
|
@ -6018,10 +6054,9 @@ class Parser(Tokenizer):
|
|||
if returnType.isVoid():
|
||||
raise WebIDLError("getter cannot have void return type",
|
||||
[self.getLocation(p, 2)])
|
||||
if setter or creator:
|
||||
if setter:
|
||||
if len(arguments) != 2:
|
||||
raise WebIDLError("%s has wrong number of arguments" %
|
||||
("setter" if setter else "creator"),
|
||||
raise WebIDLError("setter has wrong number of arguments",
|
||||
[self.getLocation(p, 2)])
|
||||
argType = arguments[0].type
|
||||
if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]:
|
||||
|
@ -6029,18 +6064,15 @@ class Parser(Tokenizer):
|
|||
elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]:
|
||||
specialType = IDLMethod.NamedOrIndexed.Indexed
|
||||
else:
|
||||
raise WebIDLError("%s has wrong argument type (must be DOMString or UnsignedLong)" %
|
||||
("setter" if setter else "creator"),
|
||||
raise WebIDLError("settter has wrong argument type (must be DOMString or UnsignedLong)",
|
||||
[arguments[0].location])
|
||||
if arguments[0].optional or arguments[0].variadic:
|
||||
raise WebIDLError("%s cannot have %s argument" %
|
||||
("setter" if setter else "creator",
|
||||
"optional" if arguments[0].optional else "variadic"),
|
||||
raise WebIDLError("setter cannot have %s argument" %
|
||||
("optional" if arguments[0].optional else "variadic"),
|
||||
[arguments[0].location])
|
||||
if arguments[1].optional or arguments[1].variadic:
|
||||
raise WebIDLError("%s cannot have %s argument" %
|
||||
("setter" if setter else "creator",
|
||||
"optional" if arguments[1].optional else "variadic"),
|
||||
raise WebIDLError("setter cannot have %s argument" %
|
||||
("optional" if arguments[1].optional else "variadic"),
|
||||
[arguments[1].location])
|
||||
|
||||
if stringifier:
|
||||
|
@ -6053,7 +6085,7 @@ class Parser(Tokenizer):
|
|||
|
||||
# identifier might be None. This is only permitted for special methods.
|
||||
if not identifier:
|
||||
if (not getter and not setter and not creator and
|
||||
if (not getter and not setter and
|
||||
not deleter and not legacycaller and not stringifier):
|
||||
raise WebIDLError("Identifier required for non-special methods",
|
||||
[self.getLocation(p, 2)])
|
||||
|
@ -6061,19 +6093,18 @@ class Parser(Tokenizer):
|
|||
location = BuiltinLocation("<auto-generated-identifier>")
|
||||
identifier = IDLUnresolvedIdentifier(
|
||||
location,
|
||||
"__%s%s%s%s%s%s%s" %
|
||||
"__%s%s%s%s%s%s" %
|
||||
("named" if specialType == IDLMethod.NamedOrIndexed.Named else
|
||||
"indexed" if specialType == IDLMethod.NamedOrIndexed.Indexed else "",
|
||||
"getter" if getter else "",
|
||||
"setter" if setter else "",
|
||||
"deleter" if deleter else "",
|
||||
"creator" if creator else "",
|
||||
"legacycaller" if legacycaller else "",
|
||||
"stringifier" if stringifier else ""),
|
||||
allowDoubleUnderscore=True)
|
||||
|
||||
method = IDLMethod(self.getLocation(p, 2), identifier, returnType, arguments,
|
||||
static=static, getter=getter, setter=setter, creator=creator,
|
||||
static=static, getter=getter, setter=setter,
|
||||
deleter=deleter, specialType=specialType,
|
||||
legacycaller=legacycaller, stringifier=stringifier)
|
||||
p[0] = method
|
||||
|
@ -6149,12 +6180,6 @@ class Parser(Tokenizer):
|
|||
"""
|
||||
p[0] = IDLMethod.Special.Setter
|
||||
|
||||
def p_SpecialCreator(self, p):
|
||||
"""
|
||||
Special : CREATOR
|
||||
"""
|
||||
p[0] = IDLMethod.Special.Creator
|
||||
|
||||
def p_SpecialDeleter(self, p):
|
||||
"""
|
||||
Special : DELETER
|
||||
|
@ -6246,7 +6271,6 @@ class Parser(Tokenizer):
|
|||
| ATTRIBUTE
|
||||
| CALLBACK
|
||||
| CONST
|
||||
| CREATOR
|
||||
| DELETER
|
||||
| DICTIONARY
|
||||
| ENUM
|
||||
|
@ -6396,7 +6420,6 @@ class Parser(Tokenizer):
|
|||
| BYTE
|
||||
| LEGACYCALLER
|
||||
| CONST
|
||||
| CREATOR
|
||||
| DELETER
|
||||
| DOUBLE
|
||||
| EXCEPTION
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue