зеркало из https://github.com/mozilla/gecko-dev.git
Bug 761772. Add support for 'implements' in WebIDL. r=khuey
This commit is contained in:
Родитель
160db69b19
Коммит
898e465bbb
|
@ -83,6 +83,7 @@ bindinggen_dependencies := \
|
||||||
Bindings.conf \
|
Bindings.conf \
|
||||||
Configuration.py \
|
Configuration.py \
|
||||||
Codegen.py \
|
Codegen.py \
|
||||||
|
parser/WebIDL.py \
|
||||||
ParserResults.pkl \
|
ParserResults.pkl \
|
||||||
$(GLOBAL_DEPS) \
|
$(GLOBAL_DEPS) \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
@ -120,6 +121,7 @@ globalgen_dependencies := \
|
||||||
Bindings.conf \
|
Bindings.conf \
|
||||||
Configuration.py \
|
Configuration.py \
|
||||||
Codegen.py \
|
Codegen.py \
|
||||||
|
parser/WebIDL.py \
|
||||||
$(CACHE_DIR)/.done \
|
$(CACHE_DIR)/.done \
|
||||||
$(GLOBAL_DEPS) \
|
$(GLOBAL_DEPS) \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
|
@ -51,15 +51,19 @@ def enum(*names):
|
||||||
return Foo()
|
return Foo()
|
||||||
|
|
||||||
class WebIDLError(Exception):
|
class WebIDLError(Exception):
|
||||||
def __init__(self, message, location, warning=False):
|
def __init__(self, message, location, warning=False, extraLocation=""):
|
||||||
self.message = message
|
self.message = message
|
||||||
self.location = location
|
self.location = location
|
||||||
self.warning = warning
|
self.warning = warning
|
||||||
|
self.extraLocation = extraLocation
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s: %s%s%s" % (self.warning and 'warning' or 'error',
|
return "%s: %s%s%s%s%s" % (self.warning and 'warning' or 'error',
|
||||||
self.message, ", " if self.location else "",
|
self.message,
|
||||||
self.location)
|
", " if self.location else "",
|
||||||
|
self.location,
|
||||||
|
"\n" if self.extraLocation else "",
|
||||||
|
self.extraLocation)
|
||||||
|
|
||||||
class Location(object):
|
class Location(object):
|
||||||
def __init__(self, lexer, lineno, lexpos, filename):
|
def __init__(self, lexer, lineno, lexpos, filename):
|
||||||
|
@ -313,7 +317,7 @@ class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope):
|
||||||
IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
|
IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
|
||||||
IDLScope.__init__(self, location, parentScope, self.identifier)
|
IDLScope.__init__(self, location, parentScope, self.identifier)
|
||||||
|
|
||||||
class IDLParentPlaceholder(IDLObjectWithIdentifier):
|
class IDLInterfacePlaceholder(IDLObjectWithIdentifier):
|
||||||
def __init__(self, location, identifier):
|
def __init__(self, location, identifier):
|
||||||
assert isinstance(identifier, IDLUnresolvedIdentifier)
|
assert isinstance(identifier, IDLUnresolvedIdentifier)
|
||||||
IDLObjectWithIdentifier.__init__(self, location, None, identifier)
|
IDLObjectWithIdentifier.__init__(self, location, None, identifier)
|
||||||
|
@ -354,12 +358,13 @@ class IDLInterface(IDLObjectWithScope):
|
||||||
def __init__(self, location, parentScope, name, parent, members):
|
def __init__(self, location, parentScope, name, parent, members):
|
||||||
assert isinstance(parentScope, IDLScope)
|
assert isinstance(parentScope, IDLScope)
|
||||||
assert isinstance(name, IDLUnresolvedIdentifier)
|
assert isinstance(name, IDLUnresolvedIdentifier)
|
||||||
assert not parent or isinstance(parent, IDLParentPlaceholder)
|
assert not parent or isinstance(parent, IDLInterfacePlaceholder)
|
||||||
|
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self._callback = False
|
self._callback = False
|
||||||
self._finished = False
|
self._finished = False
|
||||||
self.members = list(members) # clone the list
|
self.members = list(members) # clone the list
|
||||||
|
self.implementedInterfaces = set()
|
||||||
|
|
||||||
IDLObjectWithScope.__init__(self, location, parentScope, name)
|
IDLObjectWithScope.__init__(self, location, parentScope, name)
|
||||||
|
|
||||||
|
@ -398,7 +403,7 @@ class IDLInterface(IDLObjectWithScope):
|
||||||
|
|
||||||
self._finished = True
|
self._finished = True
|
||||||
|
|
||||||
assert not self.parent or isinstance(self.parent, IDLParentPlaceholder)
|
assert not self.parent or isinstance(self.parent, IDLInterfacePlaceholder)
|
||||||
parent = self.parent.finish(scope) if self.parent else None
|
parent = self.parent.finish(scope) if self.parent else None
|
||||||
assert not parent or isinstance(parent, IDLInterface)
|
assert not parent or isinstance(parent, IDLInterface)
|
||||||
|
|
||||||
|
@ -408,31 +413,57 @@ class IDLInterface(IDLObjectWithScope):
|
||||||
|
|
||||||
if self.parent:
|
if self.parent:
|
||||||
self.parent.finish(scope)
|
self.parent.finish(scope)
|
||||||
assert iter(self.parent.members)
|
|
||||||
|
|
||||||
members = list(self.parent.members)
|
# Callbacks must not inherit from non-callbacks or inherit from
|
||||||
members.extend(self.members)
|
# anything that has consequential interfaces.
|
||||||
else:
|
if self.isCallback():
|
||||||
members = list(self.members)
|
assert(self.parent.isCallback())
|
||||||
|
assert(len(self.parent.getConsequentialInterfaces()) == 0)
|
||||||
|
|
||||||
def memberNotOnParentChain(member, iface):
|
for iface in self.implementedInterfaces:
|
||||||
assert iface
|
iface.finish(scope)
|
||||||
|
|
||||||
if not iface.parent:
|
# Now resolve() and finish() our members before importing the
|
||||||
return True
|
# ones from our implemented interfaces.
|
||||||
|
|
||||||
assert isinstance(iface.parent, IDLInterface)
|
# resolve() will modify self.members, so we need to iterate
|
||||||
if member in iface.parent.members:
|
# over a copy of the member list here.
|
||||||
return False
|
for member in list(self.members):
|
||||||
return memberNotOnParentChain(member, iface.parent)
|
member.resolve(self)
|
||||||
|
|
||||||
|
for member in self.members:
|
||||||
|
member.finish(scope)
|
||||||
|
|
||||||
|
ctor = self.ctor()
|
||||||
|
if ctor is not None:
|
||||||
|
ctor.finish(scope)
|
||||||
|
|
||||||
|
# Make a copy of our member list, so things tht implement us
|
||||||
|
# can get those without all the stuff we implement ourselves
|
||||||
|
# admixed.
|
||||||
|
self.originalMembers = list(self.members)
|
||||||
|
|
||||||
|
# Import everything from our consequential interfaces into
|
||||||
|
# self.members. Sort our consequential interfaces by name
|
||||||
|
# just so we have a consistent order.
|
||||||
|
for iface in sorted(self.getConsequentialInterfaces(),
|
||||||
|
cmp=cmp,
|
||||||
|
key=lambda x: x.identifier.name):
|
||||||
|
additionalMembers = iface.originalMembers;
|
||||||
|
for additionalMember in additionalMembers:
|
||||||
|
for member in self.members:
|
||||||
|
if additionalMember.identifier.name == member.identifier.name:
|
||||||
|
raise WebIDLError(
|
||||||
|
"Multiple definitions of %s on %s coming from 'implements' statements" %
|
||||||
|
(member.identifier.name, self),
|
||||||
|
additionalMember.location,
|
||||||
|
extraLocation=member.location)
|
||||||
|
self.members.extend(additionalMembers)
|
||||||
|
|
||||||
# Ensure that there's at most one of each {named,indexed}
|
# Ensure that there's at most one of each {named,indexed}
|
||||||
# {getter,setter,creator,deleter}.
|
# {getter,setter,creator,deleter}.
|
||||||
specialMembersSeen = set()
|
specialMembersSeen = set()
|
||||||
for member in members:
|
for member in self.members:
|
||||||
if memberNotOnParentChain(member, self):
|
|
||||||
member.resolve(self)
|
|
||||||
|
|
||||||
if member.tag != IDLInterfaceMember.Tags.Method:
|
if member.tag != IDLInterfaceMember.Tags.Method:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -460,13 +491,6 @@ class IDLInterface(IDLObjectWithScope):
|
||||||
|
|
||||||
specialMembersSeen.add(memberType)
|
specialMembersSeen.add(memberType)
|
||||||
|
|
||||||
for member in self.members:
|
|
||||||
member.finish(scope)
|
|
||||||
|
|
||||||
ctor = self.ctor()
|
|
||||||
if ctor is not None:
|
|
||||||
ctor.finish(scope)
|
|
||||||
|
|
||||||
def isInterface(self):
|
def isInterface(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -531,6 +555,39 @@ class IDLInterface(IDLObjectWithScope):
|
||||||
|
|
||||||
self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
|
self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
|
||||||
|
|
||||||
|
def addImplementedInterface(self, implementedInterface):
|
||||||
|
assert(isinstance(implementedInterface, IDLInterface))
|
||||||
|
self.implementedInterfaces.add(implementedInterface)
|
||||||
|
|
||||||
|
def getInheritedInterfaces(self):
|
||||||
|
"""
|
||||||
|
Returns a list of the interfaces this interface inherits from
|
||||||
|
(not including this interface itself). The list is in order
|
||||||
|
from most derived to least derived.
|
||||||
|
"""
|
||||||
|
assert(self._finished)
|
||||||
|
if not self.parent:
|
||||||
|
return []
|
||||||
|
parentInterfaces = self.parent.getInheritedInterfaces()
|
||||||
|
parentInterfaces.insert(0, self.parent)
|
||||||
|
return parentInterfaces
|
||||||
|
|
||||||
|
def getConsequentialInterfaces(self):
|
||||||
|
assert(self._finished)
|
||||||
|
# The interfaces we implement directly
|
||||||
|
consequentialInterfaces = set(self.implementedInterfaces)
|
||||||
|
|
||||||
|
# And their inherited interfaces
|
||||||
|
for iface in self.implementedInterfaces:
|
||||||
|
consequentialInterfaces |= set(iface.getInheritedInterfaces())
|
||||||
|
|
||||||
|
# And now collect up the consequential interfaces of all of those
|
||||||
|
temp = set()
|
||||||
|
for iface in consequentialInterfaces:
|
||||||
|
temp |= iface.getConsequentialInterfaces()
|
||||||
|
|
||||||
|
return consequentialInterfaces | temp
|
||||||
|
|
||||||
class IDLEnum(IDLObjectWithIdentifier):
|
class IDLEnum(IDLObjectWithIdentifier):
|
||||||
def __init__(self, location, parentScope, name, values):
|
def __init__(self, location, parentScope, name, values):
|
||||||
assert isinstance(parentScope, IDLScope)
|
assert isinstance(parentScope, IDLScope)
|
||||||
|
@ -1740,6 +1797,22 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||||
assert not isinstance(type.name, IDLUnresolvedIdentifier)
|
assert not isinstance(type.name, IDLUnresolvedIdentifier)
|
||||||
argument.type = type
|
argument.type = type
|
||||||
|
|
||||||
|
class IDLImplementsStatement(IDLObject):
|
||||||
|
def __init__(self, location, implementor, implementee):
|
||||||
|
IDLObject.__init__(self, location)
|
||||||
|
self.implementor = implementor;
|
||||||
|
self.implementee = implementee
|
||||||
|
|
||||||
|
def finish(self, scope):
|
||||||
|
assert(isinstance(self.implementor, IDLInterfacePlaceholder))
|
||||||
|
assert(isinstance(self.implementee, IDLInterfacePlaceholder))
|
||||||
|
implementor = self.implementor.finish(scope)
|
||||||
|
implementee = self.implementee.finish(scope)
|
||||||
|
implementor.addImplementedInterface(implementee)
|
||||||
|
|
||||||
|
def addExtendedAttributes(self, attrs):
|
||||||
|
assert len(attrs) == 0
|
||||||
|
|
||||||
# Parser
|
# Parser
|
||||||
|
|
||||||
class Tokenizer(object):
|
class Tokenizer(object):
|
||||||
|
@ -1968,7 +2041,7 @@ class Parser(Tokenizer):
|
||||||
"""
|
"""
|
||||||
Inheritance : COLON ScopedName
|
Inheritance : COLON ScopedName
|
||||||
"""
|
"""
|
||||||
p[0] = IDLParentPlaceholder(self.getLocation(p, 2), p[2])
|
p[0] = IDLInterfacePlaceholder(self.getLocation(p, 2), p[2])
|
||||||
|
|
||||||
def p_InheritanceEmpty(self, p):
|
def p_InheritanceEmpty(self, p):
|
||||||
"""
|
"""
|
||||||
|
@ -2093,7 +2166,11 @@ class Parser(Tokenizer):
|
||||||
"""
|
"""
|
||||||
ImplementsStatement : ScopedName IMPLEMENTS ScopedName SEMICOLON
|
ImplementsStatement : ScopedName IMPLEMENTS ScopedName SEMICOLON
|
||||||
"""
|
"""
|
||||||
pass
|
assert(p[2] == "implements")
|
||||||
|
implementor = IDLInterfacePlaceholder(self.getLocation(p, 1), p[1])
|
||||||
|
implementee = IDLInterfacePlaceholder(self.getLocation(p, 3), p[3])
|
||||||
|
p[0] = IDLImplementsStatement(self.getLocation(p, 1), implementor,
|
||||||
|
implementee)
|
||||||
|
|
||||||
def p_Const(self, p):
|
def p_Const(self, p):
|
||||||
"""
|
"""
|
||||||
|
@ -2950,7 +3027,16 @@ class Parser(Tokenizer):
|
||||||
self._filename = None
|
self._filename = None
|
||||||
|
|
||||||
def finish(self):
|
def finish(self):
|
||||||
for production in self._productions:
|
# First, finish all the IDLImplementsStatements. In particular, we
|
||||||
|
# have to make sure we do those before we do the IDLInterfaces.
|
||||||
|
# XXX khuey hates this bit and wants to nuke it from orbit.
|
||||||
|
implementsStatements = [ p for p in self._productions if
|
||||||
|
isinstance(p, IDLImplementsStatement)]
|
||||||
|
otherStatements = [ p for p in self._productions if
|
||||||
|
not isinstance(p, IDLImplementsStatement)]
|
||||||
|
for production in implementsStatements:
|
||||||
|
production.finish(self.globalScope())
|
||||||
|
for production in otherStatements:
|
||||||
production.finish(self.globalScope())
|
production.finish(self.globalScope())
|
||||||
|
|
||||||
# De-duplicate self._productions, without modifying its order.
|
# De-duplicate self._productions, without modifying its order.
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
# Import the WebIDL module, so we can do isinstance checks and whatnot
|
||||||
|
import WebIDL
|
||||||
|
|
||||||
|
def WebIDLTest(parser, harness):
|
||||||
|
# Basic functionality
|
||||||
|
threw = False
|
||||||
|
try:
|
||||||
|
parser.parse("""
|
||||||
|
A implements B;
|
||||||
|
interface B {
|
||||||
|
attribute long x;
|
||||||
|
};
|
||||||
|
interface A {
|
||||||
|
attribute long y;
|
||||||
|
};
|
||||||
|
""")
|
||||||
|
results = parser.finish()
|
||||||
|
except:
|
||||||
|
threw = True
|
||||||
|
|
||||||
|
harness.ok(not threw, "Should not have thrown on implements statement "
|
||||||
|
"before interfaces")
|
||||||
|
harness.check(len(results), 3, "We have three statements")
|
||||||
|
harness.ok(isinstance(results[1], WebIDL.IDLInterface), "B is an interface")
|
||||||
|
harness.check(len(results[1].members), 1, "B has one member")
|
||||||
|
A = results[2]
|
||||||
|
harness.ok(isinstance(A, WebIDL.IDLInterface), "A is an interface")
|
||||||
|
harness.check(len(A.members), 2, "A has two members")
|
||||||
|
harness.check(A.members[0].identifier.name, "y", "First member is 'y'")
|
||||||
|
harness.check(A.members[1].identifier.name, "x", "Second member is 'x'")
|
||||||
|
|
||||||
|
# Duplicated member names not allowed
|
||||||
|
threw = False
|
||||||
|
try:
|
||||||
|
parser.parse("""
|
||||||
|
C implements D;
|
||||||
|
interface D {
|
||||||
|
attribute long x;
|
||||||
|
};
|
||||||
|
interface C {
|
||||||
|
attribute long x;
|
||||||
|
};
|
||||||
|
""")
|
||||||
|
parser.finish()
|
||||||
|
except:
|
||||||
|
threw = True
|
||||||
|
|
||||||
|
harness.ok(threw, "Should have thrown on implemented interface duplicating "
|
||||||
|
"a name on base interface")
|
||||||
|
|
||||||
|
# Same, but duplicated across implemented interfaces
|
||||||
|
threw = False
|
||||||
|
try:
|
||||||
|
parser.parse("""
|
||||||
|
E implements F;
|
||||||
|
E implements G;
|
||||||
|
interface F {
|
||||||
|
attribute long x;
|
||||||
|
};
|
||||||
|
interface G {
|
||||||
|
attribute long x;
|
||||||
|
};
|
||||||
|
interface E {};
|
||||||
|
""")
|
||||||
|
parser.finish()
|
||||||
|
except:
|
||||||
|
threw = True
|
||||||
|
|
||||||
|
harness.ok(threw, "Should have thrown on implemented interfaces "
|
||||||
|
"duplicating each other's member names")
|
||||||
|
|
||||||
|
# Same, but duplicated across indirectly implemented interfaces
|
||||||
|
threw = False
|
||||||
|
try:
|
||||||
|
parser.parse("""
|
||||||
|
H implements I;
|
||||||
|
H implements J;
|
||||||
|
I implements K;
|
||||||
|
interface K {
|
||||||
|
attribute long x;
|
||||||
|
};
|
||||||
|
interface L {
|
||||||
|
attribute long x;
|
||||||
|
};
|
||||||
|
interface I {};
|
||||||
|
interface J : L {};
|
||||||
|
interface H {};
|
||||||
|
""")
|
||||||
|
parser.finish()
|
||||||
|
except:
|
||||||
|
threw = True
|
||||||
|
|
||||||
|
harness.ok(threw, "Should have thrown on indirectly implemented interfaces "
|
||||||
|
"duplicating each other's member names")
|
||||||
|
|
||||||
|
# Same, but duplicated across an implemented interface and its parent
|
||||||
|
threw = False
|
||||||
|
try:
|
||||||
|
parser.parse("""
|
||||||
|
M implements N;
|
||||||
|
interface O {
|
||||||
|
attribute long x;
|
||||||
|
};
|
||||||
|
interface N : O {
|
||||||
|
attribute long x;
|
||||||
|
};
|
||||||
|
interface M {};
|
||||||
|
""")
|
||||||
|
parser.finish()
|
||||||
|
except:
|
||||||
|
threw = True
|
||||||
|
|
||||||
|
harness.ok(threw, "Should have thrown on implemented interface and its "
|
||||||
|
"ancestor duplicating member names")
|
||||||
|
|
||||||
|
# Reset the parser so we can actually find things where we expect
|
||||||
|
# them in the list
|
||||||
|
parser = WebIDL.Parser()
|
||||||
|
|
||||||
|
# Diamonds should be allowed
|
||||||
|
threw = False
|
||||||
|
try:
|
||||||
|
parser.parse("""
|
||||||
|
P implements Q;
|
||||||
|
P implements R;
|
||||||
|
Q implements S;
|
||||||
|
R implements S;
|
||||||
|
interface Q {};
|
||||||
|
interface R {};
|
||||||
|
interface S {
|
||||||
|
attribute long x;
|
||||||
|
};
|
||||||
|
interface P {};
|
||||||
|
""")
|
||||||
|
results = parser.finish()
|
||||||
|
except:
|
||||||
|
threw = True
|
||||||
|
|
||||||
|
harness.ok(not threw, "Diamond inheritance is fine")
|
||||||
|
harness.check(results[6].identifier.name, "S", "We should be looking at 'S'")
|
||||||
|
harness.check(len(results[6].members), 1, "S should have one member")
|
||||||
|
harness.check(results[6].members[0].identifier.name, "x",
|
||||||
|
"S's member should be 'x'")
|
|
@ -43,6 +43,7 @@ bindinggen_dependencies := \
|
||||||
../Bindings.conf \
|
../Bindings.conf \
|
||||||
../Configuration.py \
|
../Configuration.py \
|
||||||
../Codegen.py \
|
../Codegen.py \
|
||||||
|
../parser/WebIDL.py \
|
||||||
../ParserResults.pkl \
|
../ParserResults.pkl \
|
||||||
../Makefile \
|
../Makefile \
|
||||||
$(GLOBAL_DEPS) \
|
$(GLOBAL_DEPS) \
|
||||||
|
|
|
@ -294,6 +294,18 @@ public:
|
||||||
int8_t GetAttributeRenamedTo(ErrorResult&);
|
int8_t GetAttributeRenamedTo(ErrorResult&);
|
||||||
void SetAttributeRenamedTo(int8_t, ErrorResult&);
|
void SetAttributeRenamedTo(int8_t, ErrorResult&);
|
||||||
|
|
||||||
|
// Methods and properties imported via "implements"
|
||||||
|
bool GetImplementedProperty(ErrorResult&);
|
||||||
|
void SetImplementedProperty(bool, ErrorResult&);
|
||||||
|
void ImplementedMethod(ErrorResult&);
|
||||||
|
bool GetImplementedParentProperty(ErrorResult&);
|
||||||
|
void SetImplementedParentProperty(bool, ErrorResult&);
|
||||||
|
void ImplementedParentMethod(ErrorResult&);
|
||||||
|
bool GetIndirectlyImplementedProperty(ErrorResult&);
|
||||||
|
void SetIndirectlyImplementedProperty(bool, ErrorResult&);
|
||||||
|
void IndirectlyImplementedMethod(ErrorResult&);
|
||||||
|
uint32_t GetDiamondImplementedProperty(ErrorResult&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// We add signatures here that _could_ start matching if the codegen
|
// We add signatures here that _could_ start matching if the codegen
|
||||||
// got data types wrong. That way if it ever does we'll have a call
|
// got data types wrong. That way if it ever does we'll have a call
|
||||||
|
|
|
@ -16,6 +16,8 @@ enum TestEnum {
|
||||||
|
|
||||||
callback TestCallback = void();
|
callback TestCallback = void();
|
||||||
|
|
||||||
|
TestInterface implements ImplementedInterface;
|
||||||
|
|
||||||
[Constructor,
|
[Constructor,
|
||||||
Constructor(DOMString str),
|
Constructor(DOMString str),
|
||||||
Constructor(unsigned long num, boolean? bool),
|
Constructor(unsigned long num, boolean? bool),
|
||||||
|
@ -223,3 +225,44 @@ interface TestInterface {
|
||||||
readonly attribute byte attributeGetterRenamedFrom;
|
readonly attribute byte attributeGetterRenamedFrom;
|
||||||
attribute byte attributeRenamedFrom;
|
attribute byte attributeRenamedFrom;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface ImplementedInterfaceParent {
|
||||||
|
void implementedParentMethod();
|
||||||
|
attribute boolean implementedParentProperty;
|
||||||
|
|
||||||
|
const long implementedParentConstant = 8;
|
||||||
|
};
|
||||||
|
|
||||||
|
ImplementedInterfaceParent implements IndirectlyImplementedInterface;
|
||||||
|
|
||||||
|
interface IndirectlyImplementedInterface {
|
||||||
|
void indirectlyImplementedMethod();
|
||||||
|
attribute boolean indirectlyImplementedProperty;
|
||||||
|
|
||||||
|
const long indirectlyImplementedConstant = 9;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ImplementedInterface : ImplementedInterfaceParent {
|
||||||
|
void implementedMethod();
|
||||||
|
attribute boolean implementedProperty;
|
||||||
|
|
||||||
|
const long implementedConstant = 5;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface DiamondImplements {
|
||||||
|
readonly attribute long diamondImplementedProperty;
|
||||||
|
};
|
||||||
|
interface DiamondBranch1A {
|
||||||
|
};
|
||||||
|
interface DiamondBranch1B {
|
||||||
|
};
|
||||||
|
interface DiamondBranch2A : DiamondImplements {
|
||||||
|
};
|
||||||
|
interface DiamondBranch2B : DiamondImplements {
|
||||||
|
};
|
||||||
|
TestInterface implements DiamondBranch1A;
|
||||||
|
TestInterface implements DiamondBranch1B;
|
||||||
|
TestInterface implements DiamondBranch2A;
|
||||||
|
TestInterface implements DiamondBranch2B;
|
||||||
|
DiamondBranch1A implements DiamondImplements;
|
||||||
|
DiamondBranch1B implements DiamondImplements;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче