зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1578173 part 1. Add support for constructor operations in the parser. r=edgar
The grammar changes parallel those in https://github.com/heycam/webidl/pull/700 We don't prevent having both a constructor operation and [Constructor] or [ChromeConstructor], because those extended attributes are about to get removed, once they are no longer used in our IDL. Differential Revision: https://phabricator.services.mozilla.com/D45387 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
c873e19b84
Коммит
c0dd336d70
|
@ -1077,9 +1077,20 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
|
|||
|
||||
ctor = self.ctor()
|
||||
if ctor is not None:
|
||||
assert len(ctor._exposureGlobalNames) == 0
|
||||
if not self.hasInterfaceObject():
|
||||
raise WebIDLError(
|
||||
"Can't have both a constructor and [NoInterfaceObject]",
|
||||
[self.location, ctor.location])
|
||||
|
||||
assert(len(ctor._exposureGlobalNames) == 0 or
|
||||
ctor._exposureGlobalNames == self._exposureGlobalNames)
|
||||
ctor._exposureGlobalNames.update(self._exposureGlobalNames)
|
||||
ctor.finish(scope)
|
||||
if ctor in self.members:
|
||||
# constructor operation.
|
||||
self.members.remove(ctor)
|
||||
else:
|
||||
# extended attribute.
|
||||
ctor.finish(scope)
|
||||
|
||||
for ctor in self.namedConstructors:
|
||||
assert len(ctor._exposureGlobalNames) == 0
|
||||
|
@ -1741,19 +1752,15 @@ class IDLInterface(IDLInterfaceOrNamespace):
|
|||
name = attr.value()
|
||||
allowForbidden = False
|
||||
|
||||
methodIdentifier = IDLUnresolvedIdentifier(self.location, name,
|
||||
allowForbidden=allowForbidden)
|
||||
method = IDLConstructor(
|
||||
attr.location, args, name,
|
||||
htmlConstructor=(identifier == "HTMLConstructor"))
|
||||
method.reallyInit(self)
|
||||
|
||||
method = IDLMethod(self.location, methodIdentifier, retType,
|
||||
args, static=True,
|
||||
htmlConstructor=(identifier == "HTMLConstructor"))
|
||||
# Constructors are always NewObject and are always
|
||||
# assumed to be able to throw (since there's no way to
|
||||
# indicate otherwise) and never have any other
|
||||
# extended attributes.
|
||||
# Are always assumed to be able to throw (since there's no way to
|
||||
# indicate otherwise).
|
||||
method.addExtendedAttributes(
|
||||
[IDLExtendedAttribute(self.location, ("NewObject",)),
|
||||
IDLExtendedAttribute(self.location, ("Throws",))])
|
||||
[IDLExtendedAttribute(self.location, ("Throws",))])
|
||||
if identifier == "ChromeConstructor":
|
||||
method.addExtendedAttributes(
|
||||
[IDLExtendedAttribute(self.location, ("ChromeOnly",))])
|
||||
|
@ -1887,6 +1894,17 @@ class IDLInterface(IDLInterfaceOrNamespace):
|
|||
def isSerializable(self):
|
||||
return self.getExtendedAttribute("Serializable")
|
||||
|
||||
def setNonPartial(self, location, parent, members):
|
||||
# Before we do anything else, finish initializing any constructors that
|
||||
# might be in "members", so we don't have partially-initialized objects
|
||||
# hanging around. We couldn't do it before now because we needed to have
|
||||
# to have the IDLInterface on hand to properly set the return type.
|
||||
for member in members:
|
||||
if isinstance(member, IDLConstructor):
|
||||
member.reallyInit(self)
|
||||
|
||||
IDLInterfaceOrNamespace.setNonPartial(self, location, parent, members)
|
||||
|
||||
|
||||
class IDLNamespace(IDLInterfaceOrNamespace):
|
||||
def __init__(self, location, parentScope, name, members, isKnownNonPartial):
|
||||
|
@ -5481,6 +5499,52 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
return deps
|
||||
|
||||
|
||||
class IDLConstructor(IDLMethod):
|
||||
def __init__(self, location, args, name, htmlConstructor=False):
|
||||
# We can't actually init our IDLMethod yet, because we do not know the
|
||||
# return type yet. Just save the info we have for now and we will init
|
||||
# it later.
|
||||
self._initLocation = location
|
||||
self._initArgs = args
|
||||
self._initName = name
|
||||
self._htmlConstructor = htmlConstructor
|
||||
self._inited = False
|
||||
self._initExtendedAttrs = []
|
||||
|
||||
def addExtendedAttributes(self, attrs):
|
||||
if self._inited:
|
||||
return IDLMethod.addExtendedAttributes(self, attrs)
|
||||
self._initExtendedAttrs.extend(attrs)
|
||||
|
||||
def handleExtendedAttribute(self, attr):
|
||||
identifier = attr.identifier()
|
||||
if (identifier == "BinaryName" or
|
||||
identifier == "ChromeOnly" or
|
||||
identifier == "NewObject" or
|
||||
identifier == "SecureContext" or
|
||||
identifier == "Throws"):
|
||||
IDLMethod.handleExtendedAttribute(self, attr)
|
||||
else:
|
||||
raise WebIDLError("Unknown extended attribute %s on method" % identifier,
|
||||
[attr.location])
|
||||
|
||||
def reallyInit(self, parentInterface):
|
||||
name = self._initName
|
||||
location = self._initLocation
|
||||
identifier = IDLUnresolvedIdentifier(location, name, allowForbidden=True)
|
||||
retType = IDLWrapperType(parentInterface.location, parentInterface)
|
||||
IDLMethod.__init__(self, location, identifier, retType, self._initArgs,
|
||||
static=True, htmlConstructor=self._htmlConstructor)
|
||||
self._inited = True;
|
||||
# Propagate through whatever extended attributes we already had
|
||||
self.addExtendedAttributes(self._initExtendedAttrs)
|
||||
self._initExtendedAttrs = []
|
||||
# Constructors are always NewObject. Whether they throw or not is
|
||||
# indicated by [Throws] annotations in the usual way.
|
||||
self.addExtendedAttributes(
|
||||
[IDLExtendedAttribute(self.location, ("NewObject",))])
|
||||
|
||||
|
||||
class IDLImplementsStatement(IDLObject):
|
||||
def __init__(self, location, implementor, implementee):
|
||||
IDLObject.__init__(self, location)
|
||||
|
@ -6061,7 +6125,7 @@ class Parser(Tokenizer):
|
|||
|
||||
def p_PartialInterfaceRest(self, p):
|
||||
"""
|
||||
PartialInterfaceRest : IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON
|
||||
PartialInterfaceRest : IDENTIFIER LBRACE PartialInterfaceMembers RBRACE SEMICOLON
|
||||
"""
|
||||
location = self.getLocation(p, 1)
|
||||
identifier = IDLUnresolvedIdentifier(location, p[1])
|
||||
|
@ -6142,8 +6206,38 @@ class Parser(Tokenizer):
|
|||
|
||||
def p_InterfaceMember(self, p):
|
||||
"""
|
||||
InterfaceMember : Const
|
||||
| AttributeOrOperationOrMaplikeOrSetlikeOrIterable
|
||||
InterfaceMember : PartialInterfaceMember
|
||||
| Constructor
|
||||
"""
|
||||
p[0] = p[1]
|
||||
|
||||
def p_Constructor(self, p):
|
||||
"""
|
||||
Constructor : CONSTRUCTOR LPAREN ArgumentList RPAREN SEMICOLON
|
||||
"""
|
||||
p[0] = IDLConstructor(self.getLocation(p, 1), p[3], "constructor")
|
||||
|
||||
def p_PartialInterfaceMembers(self, p):
|
||||
"""
|
||||
PartialInterfaceMembers : ExtendedAttributeList PartialInterfaceMember PartialInterfaceMembers
|
||||
"""
|
||||
p[0] = [p[2]]
|
||||
|
||||
assert not p[1] or p[2]
|
||||
p[2].addExtendedAttributes(p[1])
|
||||
|
||||
p[0].extend(p[3])
|
||||
|
||||
def p_PartialInterfaceMembersEmpty(self, p):
|
||||
"""
|
||||
PartialInterfaceMembers :
|
||||
"""
|
||||
p[0] = []
|
||||
|
||||
def p_PartialInterfaceMember(self, p):
|
||||
"""
|
||||
PartialInterfaceMember : Const
|
||||
| AttributeOrOperationOrMaplikeOrSetlikeOrIterable
|
||||
"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
|
|
@ -57,26 +57,54 @@ def WebIDLTest(parser, harness):
|
|||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
harness.check(len(results), 3, "Should be three productions")
|
||||
harness.ok(isinstance(results[0], WebIDL.IDLInterface),
|
||||
"Should be an IDLInterface")
|
||||
harness.ok(isinstance(results[1], WebIDL.IDLInterface),
|
||||
"Should be an IDLInterface")
|
||||
harness.ok(isinstance(results[2], WebIDL.IDLInterface),
|
||||
"Should be an IDLInterface")
|
||||
|
||||
checkMethod(results[0].ctor(), "::TestConstructorNoArgs::constructor",
|
||||
"constructor", [("TestConstructorNoArgs (Wrapper)", [])])
|
||||
checkMethod(results[1].ctor(), "::TestConstructorWithArgs::constructor",
|
||||
"constructor",
|
||||
[("TestConstructorWithArgs (Wrapper)",
|
||||
[("::TestConstructorWithArgs::constructor::name", "name", "String", False, False)])])
|
||||
checkMethod(results[2].ctor(), "::TestConstructorOverloads::constructor",
|
||||
"constructor",
|
||||
[("TestConstructorOverloads (Wrapper)",
|
||||
[("::TestConstructorOverloads::constructor::foo", "foo", "Object", False, False)]),
|
||||
("TestConstructorOverloads (Wrapper)",
|
||||
[("::TestConstructorOverloads::constructor::bar", "bar", "Boolean", False, False)])])
|
||||
def checkResults(results):
|
||||
harness.check(len(results), 3, "Should be three productions")
|
||||
harness.ok(isinstance(results[0], WebIDL.IDLInterface),
|
||||
"Should be an IDLInterface")
|
||||
harness.ok(isinstance(results[1], WebIDL.IDLInterface),
|
||||
"Should be an IDLInterface")
|
||||
harness.ok(isinstance(results[2], WebIDL.IDLInterface),
|
||||
"Should be an IDLInterface")
|
||||
|
||||
checkMethod(results[0].ctor(), "::TestConstructorNoArgs::constructor",
|
||||
"constructor", [("TestConstructorNoArgs (Wrapper)", [])])
|
||||
harness.check(len(results[0].members), 0,
|
||||
"TestConstructorNoArgs should not have members")
|
||||
checkMethod(results[1].ctor(), "::TestConstructorWithArgs::constructor",
|
||||
"constructor",
|
||||
[("TestConstructorWithArgs (Wrapper)",
|
||||
[("::TestConstructorWithArgs::constructor::name", "name", "String", False, False)])])
|
||||
harness.check(len(results[1].members), 0,
|
||||
"TestConstructorWithArgs should not have members")
|
||||
checkMethod(results[2].ctor(), "::TestConstructorOverloads::constructor",
|
||||
"constructor",
|
||||
[("TestConstructorOverloads (Wrapper)",
|
||||
[("::TestConstructorOverloads::constructor::foo", "foo", "Object", False, False)]),
|
||||
("TestConstructorOverloads (Wrapper)",
|
||||
[("::TestConstructorOverloads::constructor::bar", "bar", "Boolean", False, False)])])
|
||||
harness.check(len(results[2].members), 0,
|
||||
"TestConstructorOverloads should not have members")
|
||||
|
||||
checkResults(results)
|
||||
|
||||
parser = parser.reset()
|
||||
parser.parse("""
|
||||
interface TestConstructorNoArgs {
|
||||
constructor();
|
||||
};
|
||||
|
||||
interface TestConstructorWithArgs {
|
||||
constructor(DOMString name);
|
||||
};
|
||||
|
||||
interface TestConstructorOverloads {
|
||||
constructor(object foo);
|
||||
constructor(boolean bar);
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
checkResults(results)
|
||||
|
||||
parser = parser.reset()
|
||||
parser.parse("""
|
||||
|
@ -93,6 +121,21 @@ def WebIDLTest(parser, harness):
|
|||
"constructor", [("TestChromeConstructor (Wrapper)", [])],
|
||||
chromeOnly=True)
|
||||
|
||||
parser = parser.reset()
|
||||
parser.parse("""
|
||||
interface TestChromeConstructor {
|
||||
[ChromeOnly] constructor();
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
harness.check(len(results), 1, "Should be one production")
|
||||
harness.ok(isinstance(results[0], WebIDL.IDLInterface),
|
||||
"Should be an IDLInterface")
|
||||
|
||||
checkMethod(results[0].ctor(), "::TestChromeConstructor::constructor",
|
||||
"constructor", [("TestChromeConstructor (Wrapper)", [])],
|
||||
chromeOnly=True)
|
||||
|
||||
parser = parser.reset()
|
||||
parser.parse("""
|
||||
[HTMLConstructor]
|
||||
|
@ -193,6 +236,7 @@ def WebIDLTest(parser, harness):
|
|||
interface TestHTMLConstructorAndConstructor {
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
|
@ -207,11 +251,79 @@ def WebIDLTest(parser, harness):
|
|||
interface TestHTMLConstructorAndConstructor {
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw, "Can't have both a HTMLConstructor and a Constructor")
|
||||
|
||||
# Test HTMLConstructor and constructor operation
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
[HTMLConstructor]
|
||||
interface TestHTMLConstructorAndConstructor {
|
||||
constructor();
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw, "Can't have both a constructor and a HTMLConstructor")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
[HTMLConstructor]
|
||||
interface TestHTMLConstructorAndConstructor {
|
||||
[Throws]
|
||||
constructor();
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw,
|
||||
"Can't have both a throwing constructor and a HTMLConstructor")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
[HTMLConstructor]
|
||||
interface TestHTMLConstructorAndConstructor {
|
||||
constructor(DOMString a);
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw,
|
||||
"Can't have both a HTMLConstructor and a constructor operation")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
[HTMLConstructor]
|
||||
interface TestHTMLConstructorAndConstructor {
|
||||
[Throws]
|
||||
constructor(DOMString a);
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw,
|
||||
"Can't have both a HTMLConstructor and a throwing constructor "
|
||||
"operation")
|
||||
|
||||
# Test HTMLConstructor and ChromeConstructor
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
|
@ -270,3 +382,131 @@ def WebIDLTest(parser, harness):
|
|||
threw = True
|
||||
|
||||
harness.ok(threw, "Can't have both a HTMLConstructor and a ChromeConstructor")
|
||||
|
||||
# Test HTMLConstructor and [ChromeOnly] constructor operation
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
[HTMLConstructor]
|
||||
interface TestHTMLConstructorAndConstructor {
|
||||
[ChromeOnly]
|
||||
constructor();
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw,
|
||||
"Can't have both a ChromeOnly constructor and a HTMLConstructor")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
[HTMLConstructor]
|
||||
interface TestHTMLConstructorAndConstructor {
|
||||
[Throws, ChromeOnly]
|
||||
constructor();
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw,
|
||||
"Can't have both a throwing chromeonly constructor and a "
|
||||
"HTMLConstructor")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
[HTMLConstructor]
|
||||
interface TestHTMLConstructorAndConstructor {
|
||||
[ChromeOnly]
|
||||
constructor(DOMString a);
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw,
|
||||
"Can't have both a HTMLConstructor and a chromeonly constructor "
|
||||
"operation")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
[HTMLConstructor]
|
||||
interface TestHTMLConstructorAndConstructor {
|
||||
[Throws, ChromeOnly]
|
||||
constructor(DOMString a);
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw,
|
||||
"Can't have both a HTMLConstructor and a throwing chromeonly "
|
||||
"constructor operation")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
[NoInterfaceObject]
|
||||
interface InterfaceWithoutInterfaceObject {
|
||||
constructor();
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw,
|
||||
"Can't have a constructor operation on a [NoInterfaceObject] "
|
||||
"interface")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface InterfaceWithPartial {
|
||||
};
|
||||
|
||||
partial interface InterfaceWithPartial {
|
||||
constructor();
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw,
|
||||
"Can't have a constructor operation on a partial interface")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface InterfaceWithMixin {
|
||||
};
|
||||
|
||||
interface mixin Mixin {
|
||||
constructor();
|
||||
};
|
||||
|
||||
InterfaceWithMixin includes Mixin
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw,
|
||||
"Can't have a constructor operation on a mixin")
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче