aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/bindings/codegen/parser
diff options
context:
space:
mode:
authorKagami Sascha Rosylight <saschanaz@outlook.com>2019-10-25 17:05:49 +0900
committerKagami Sascha Rosylight <saschanaz@outlook.com>2019-10-29 21:34:53 +0900
commit97c01fc4792c6bc0edd2d588470f38a7f02d9661 (patch)
tree05d43493000be2dec5881d71f9a224b38f3ae1cb /components/script/dom/bindings/codegen/parser
parent4ff24af3d50db27480b3f6d7f8f9f8d495584857 (diff)
downloadservo-97c01fc4792c6bc0edd2d588470f38a7f02d9661.tar.gz
servo-97c01fc4792c6bc0edd2d588470f38a7f02d9661.zip
Update WebIDL.py
Diffstat (limited to 'components/script/dom/bindings/codegen/parser')
-rw-r--r--components/script/dom/bindings/codegen/parser/WebIDL.py78
-rw-r--r--components/script/dom/bindings/codegen/parser/tests/test_stringifier.py100
2 files changed, 172 insertions, 6 deletions
diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py
index 215d9c1212f..b2e56c9deaf 100644
--- a/components/script/dom/bindings/codegen/parser/WebIDL.py
+++ b/components/script/dom/bindings/codegen/parser/WebIDL.py
@@ -760,6 +760,8 @@ class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMix
# specified, it already has a nonempty exposure global names set.
if len(m._exposureGlobalNames) == 0:
m._exposureGlobalNames.update(self._exposureGlobalNames)
+ if m.isAttr() and m.stringifier:
+ m.expand(self.members)
# resolve() will modify self.members, so we need to iterate
# over a copy of the member list here.
@@ -1855,6 +1857,9 @@ class IDLDictionary(IDLObjectWithScope):
self._finished = False
self.members = list(members)
self._partialDictionaries = []
+ self._extendedAttrDict = {}
+ self.needsConversionToJS = False
+ self.needsConversionFromJS = False
IDLObjectWithScope.__init__(self, location, parentScope, name)
@@ -1988,11 +1993,34 @@ class IDLDictionary(IDLObjectWithScope):
self.identifier.name,
[member.location] + locations)
+ def getExtendedAttribute(self, name):
+ return self._extendedAttrDict.get(name, None)
+
def addExtendedAttributes(self, attrs):
- if len(attrs) != 0:
- raise WebIDLError("There are no extended attributes that are "
- "allowed on dictionaries",
- [attrs[0].location, self.location])
+ for attr in attrs:
+ identifier = attr.identifier()
+
+ if (identifier == "GenerateInitFromJSON" or
+ identifier == "GenerateInit"):
+ if not attr.noArguments():
+ raise WebIDLError("[%s] must not have arguments" % identifier,
+ [attr.location])
+ self.needsConversionFromJS = True
+ elif (identifier == "GenerateConversionToJS" or
+ identifier == "GenerateToJSON"):
+ if not attr.noArguments():
+ raise WebIDLError("[%s] must not have arguments" % identifier,
+ [attr.location])
+ # ToJSON methods require to-JS conversion, because we
+ # implement ToJSON by converting to a JS object and
+ # then using JSON.stringify.
+ self.needsConversionToJS = True
+ else:
+ raise WebIDLError("[%s] extended attribute not allowed on "
+ "dictionaries" % identifier,
+ [attr.location])
+
+ self._extendedAttrDict[identifier] = True
def _getDependentObjects(self):
deps = set(self.members)
@@ -2004,6 +2032,7 @@ class IDLDictionary(IDLObjectWithScope):
assert self.identifier.name == partial.identifier.name
self._partialDictionaries.append(partial)
+
class IDLEnum(IDLObjectWithIdentifier):
def __init__(self, location, parentScope, name, values):
assert isinstance(parentScope, IDLScope)
@@ -4622,6 +4651,40 @@ class IDLAttribute(IDLInterfaceMember):
def _getDependentObjects(self):
return set([self.type])
+ def expand(self, members):
+ assert self.stringifier
+ if not self.type.isDOMString() and not self.type.isUSVString():
+ raise WebIDLError("The type of a stringifer attribute must be "
+ "either DOMString or USVString",
+ [self.location])
+ identifier = IDLUnresolvedIdentifier(self.location, "__stringifier",
+ allowDoubleUnderscore=True)
+ method = IDLMethod(self.location,
+ identifier,
+ returnType=self.type, arguments=[],
+ stringifier=True, underlyingAttr=self)
+ allowedExtAttrs = ["Throws", "NeedsSubjectPrincipal", "Pure"]
+ # Safe to ignore these as they are only meaningful for attributes
+ attributeOnlyExtAttrs = [
+ "CEReactions",
+ "CrossOriginWritable",
+ "SetterThrows",
+ ]
+ for (key, value) in self._extendedAttrDict.items():
+ if key in allowedExtAttrs:
+ if value is not True:
+ raise WebIDLError("[%s] with a value is currently "
+ "unsupported in stringifier attributes, "
+ "please file a bug to add support" % key,
+ [self.location])
+ method.addExtendedAttributes([IDLExtendedAttribute(self.location, (key,))])
+ elif not key in attributeOnlyExtAttrs:
+ raise WebIDLError("[%s] is currently unsupported in "
+ "stringifier attributes, please file a bug "
+ "to add support" % key,
+ [self.location])
+ members.append(method)
+
class IDLArgument(IDLObjectWithIdentifier):
def __init__(self, location, identifier, type, optional=False, defaultValue=None, variadic=False, dictionaryMember=False, allowTypeAttributes=False):
@@ -4867,7 +4930,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
static=False, getter=False, setter=False,
deleter=False, specialType=NamedOrIndexed.Neither,
legacycaller=False, stringifier=False,
- maplikeOrSetlikeOrIterable=None):
+ maplikeOrSetlikeOrIterable=None,
+ underlyingAttr=None):
# REVIEW: specialType is NamedOrIndexed -- wow, this is messed up.
IDLInterfaceMember.__init__(self, location, identifier,
IDLInterfaceMember.Tags.Method)
@@ -4894,6 +4958,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase)
self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable
self._htmlConstructor = False
+ self.underlyingAttr = underlyingAttr
self._specialType = specialType
self._unforgeable = False
self.dependsOn = "Everything"
@@ -4933,7 +4998,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
assert len(self._overloads) == 1
overload = self._overloads[0]
assert len(overload.arguments) == 0
- assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring]
+ if not self.underlyingAttr:
+ assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring]
def isStatic(self):
return self._static
diff --git a/components/script/dom/bindings/codegen/parser/tests/test_stringifier.py b/components/script/dom/bindings/codegen/parser/tests/test_stringifier.py
index 14c2c5226fc..deabdc5ec81 100644
--- a/components/script/dom/bindings/codegen/parser/tests/test_stringifier.py
+++ b/components/script/dom/bindings/codegen/parser/tests/test_stringifier.py
@@ -44,3 +44,103 @@ def WebIDLTest(parser, harness):
harness.ok(threw, "Should not allow a 'stringifier;' and a 'stringifier()'")
+ parser = parser.reset()
+ parser.parse("""
+ interface TestStringifier {
+ stringifier attribute DOMString foo;
+ };
+ """)
+ results = parser.finish()
+ harness.ok(isinstance(results[0].members[0], WebIDL.IDLAttribute),
+ "Stringifier attribute should be an attribute")
+ stringifier = results[0].members[1]
+ harness.ok(isinstance(stringifier, WebIDL.IDLMethod),
+ "Stringifier attribute should insert a method")
+ harness.ok(stringifier.isStringifier(),
+ "Inserted method should be a stringifier")
+
+ parser = parser.reset()
+ parser.parse("""
+ interface TestStringifier {};
+ interface mixin TestStringifierMixin {
+ stringifier attribute DOMString foo;
+ };
+ TestStringifier includes TestStringifierMixin;
+ """)
+ results = parser.finish()
+ harness.ok(isinstance(results[0].members[0], WebIDL.IDLAttribute),
+ "Stringifier attribute should be an attribute")
+ stringifier = results[0].members[1]
+ harness.ok(isinstance(stringifier, WebIDL.IDLMethod),
+ "Stringifier attribute should insert a method")
+ harness.ok(stringifier.isStringifier(),
+ "Inserted method should be a stringifier")
+
+ parser = parser.reset()
+ parser.parse("""
+ interface TestStringifier {
+ stringifier attribute USVString foo;
+ };
+ """)
+ results = parser.finish()
+ stringifier = results[0].members[1]
+ harness.ok(stringifier.signatures()[0][0].isUSVString(),
+ "Stringifier attributes should allow USVString")
+
+ parser = parser.reset()
+ parser.parse("""
+ interface TestStringifier {
+ [Throws, NeedsSubjectPrincipal]
+ stringifier attribute USVString foo;
+ };
+ """)
+ results = parser.finish()
+ stringifier = results[0].members[1]
+ harness.ok(stringifier.getExtendedAttribute("Throws"),
+ "Stringifier attributes should support [Throws]")
+ harness.ok(stringifier.getExtendedAttribute("NeedsSubjectPrincipal"),
+ "Stringifier attributes should support [NeedsSubjectPrincipal]")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse("""
+ interface TestStringifier {
+ stringifier attribute ByteString foo;
+ };
+ """)
+ results = parser.finish()
+ except:
+ threw = True
+
+ harness.ok(threw, "Should not allow ByteString")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse("""
+ interface TestStringifier {
+ stringifier;
+ stringifier attribute DOMString foo;
+ };
+ """)
+ results = parser.finish()
+ except:
+ threw = True
+
+ harness.ok(threw, "Should not allow a 'stringifier;' and a stringifier attribute")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse("""
+ interface TestStringifier {
+ stringifier attribute DOMString foo;
+ stringifier attribute DOMString bar;
+ };
+ """)
+ results = parser.finish()
+ except:
+ threw = True
+
+ harness.ok(threw, "Should not allow multiple stringifier attributes")