зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1498059 - Add CEnum types to XPIDL; r=nika,froydnj
Add CEnum types to XPIDL, allowing for typed enums in C++ instead of using uintXX_t types. Javascript will still reflect CEnums as interface level consts. Depends on D8593 Differential Revision: https://phabricator.services.mozilla.com/D8594 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
911d1c3784
Коммит
cd6f797161
|
@ -390,6 +390,12 @@ def write_interface(iface, fd):
|
|||
fd.write(",\n".join(enums))
|
||||
fd.write("\n };\n\n")
|
||||
|
||||
def write_cenum_decl(b):
|
||||
fd.write(" enum %s : uint%d_t {\n" % (b.basename, b.width))
|
||||
for var in b.variants:
|
||||
fd.write(" %s = %s,\n" % (var.name, var.value))
|
||||
fd.write(" };\n\n")
|
||||
|
||||
def write_method_decl(m):
|
||||
printComments(fd, m.doccomments, ' ')
|
||||
|
||||
|
@ -471,6 +477,8 @@ def write_interface(iface, fd):
|
|||
write_method_decl(member)
|
||||
elif key == xpidl.CDATA:
|
||||
fd.write(" %s" % member.data)
|
||||
elif key == xpidl.CEnum:
|
||||
write_cenum_decl(member)
|
||||
else:
|
||||
raise Exception("Unexpected interface member: %s" % member)
|
||||
|
||||
|
|
|
@ -105,6 +105,10 @@ def get_type(type, calltype, iid_is=None, size_is=None):
|
|||
else:
|
||||
return {'tag': 'TD_VOID'}
|
||||
|
||||
if isinstance(type, xpidl.CEnum):
|
||||
# As far as XPConnect is concerned, cenums are just unsigned integers.
|
||||
return {'tag': 'TD_UINT%d' % type.width}
|
||||
|
||||
raise Exception("Unknown type!")
|
||||
|
||||
|
||||
|
@ -166,6 +170,14 @@ def build_interface(iface):
|
|||
'value': c.getValue(), # All of our consts are numbers
|
||||
})
|
||||
|
||||
def build_cenum(b):
|
||||
for var in b.variants:
|
||||
consts.append({
|
||||
'name': var.name,
|
||||
'type': get_type(b, 'in'),
|
||||
'value': var.value,
|
||||
})
|
||||
|
||||
def build_method(m):
|
||||
params = []
|
||||
for p in m.params:
|
||||
|
@ -210,6 +222,8 @@ def build_interface(iface):
|
|||
build_attr(member)
|
||||
elif isinstance(member, xpidl.Method):
|
||||
build_method(member)
|
||||
elif isinstance(member, xpidl.CEnum):
|
||||
build_cenum(member)
|
||||
elif isinstance(member, xpidl.CDATA):
|
||||
pass
|
||||
else:
|
||||
|
|
|
@ -910,6 +910,85 @@ class ConstMember(object):
|
|||
return 0
|
||||
|
||||
|
||||
# Represents a single name/value pair in a CEnum
|
||||
class CEnumVariant(object):
|
||||
# Treat CEnumVariants as consts in terms of value resolution, so we can
|
||||
# do things like binary operation values for enum members.
|
||||
kind = 'const'
|
||||
|
||||
def __init__(self, name, value, location):
|
||||
self.name = name
|
||||
self.value = value
|
||||
self.location = location
|
||||
|
||||
def getValue(self):
|
||||
return self.value
|
||||
|
||||
|
||||
class CEnum(object):
|
||||
kind = 'cenum'
|
||||
|
||||
def __init__(self, width, name, variants, location, doccomments):
|
||||
# We have to set a name here, otherwise we won't pass namemap checks on
|
||||
# the interface. This name will change it in resolve(), in order to
|
||||
# namespace the enum within the interface.
|
||||
self.name = name
|
||||
self.basename = name
|
||||
self.width = width
|
||||
self.location = location
|
||||
self.namemap = NameMap()
|
||||
self.doccomments = doccomments
|
||||
self.variants = variants
|
||||
if self.width not in (8, 16, 32):
|
||||
raise IDLError("Width must be one of {8, 16, 32}", self.location)
|
||||
|
||||
def getValue(self):
|
||||
return self.value(self.iface)
|
||||
|
||||
def resolve(self, iface):
|
||||
self.iface = iface
|
||||
# Renaming enum to faux-namespace the enum type to the interface in JS
|
||||
# so we don't collide in the global namespace. Hacky/ugly but it does
|
||||
# the job well enough, and the name will still be interface::variant in
|
||||
# C++.
|
||||
self.name = '%s_%s' % (self.iface.name, self.basename)
|
||||
self.iface.idl.setName(self)
|
||||
|
||||
# Compute the value for each enum variant that doesn't set its own
|
||||
# value
|
||||
next_value = 0
|
||||
for variant in self.variants:
|
||||
# CEnum variants resolve to interface level consts in javascript,
|
||||
# meaning their names could collide with other interface members.
|
||||
# Iterate through all CEnum variants to make sure there are no
|
||||
# collisions.
|
||||
self.iface.namemap.set(variant)
|
||||
# Value may be a lambda. If it is, resolve it.
|
||||
if variant.value:
|
||||
next_value = variant.value = variant.value(self.iface)
|
||||
else:
|
||||
variant.value = next_value
|
||||
next_value += 1
|
||||
|
||||
def count(self):
|
||||
return 0
|
||||
|
||||
def isScriptable(self):
|
||||
return True
|
||||
|
||||
def nativeType(self, calltype):
|
||||
if 'out' in calltype:
|
||||
return "%s::%s *" % (self.iface.name, self.basename)
|
||||
return "%s::%s " % (self.iface.name, self.basename)
|
||||
|
||||
def rustType(self, calltype):
|
||||
raise RustNoncompat('cenums unimplemented')
|
||||
|
||||
def __str__(self):
|
||||
body = ', '.join('%s = %s' % v for v in self.variants)
|
||||
return "\tcenum %s : %d { %s };\n" % (self.name, self.width, body)
|
||||
|
||||
|
||||
class Attribute(object):
|
||||
kind = 'attribute'
|
||||
noscript = False
|
||||
|
@ -1267,6 +1346,7 @@ TypeId.__new__.__defaults__ = (None,)
|
|||
|
||||
class IDLParser(object):
|
||||
keywords = {
|
||||
'cenum': 'CENUM',
|
||||
'const': 'CONST',
|
||||
'interface': 'INTERFACE',
|
||||
'in': 'IN',
|
||||
|
@ -1572,6 +1652,34 @@ class IDLParser(object):
|
|||
n2 = p[3]
|
||||
p[0] = lambda i: n1(i) | n2(i)
|
||||
|
||||
def p_member_cenum(self, p):
|
||||
"""member : CENUM IDENTIFIER ':' NUMBER '{' variants '}' ';'"""
|
||||
p[0] = CEnum(name=p[2],
|
||||
width=int(p[4]),
|
||||
variants=p[6],
|
||||
location=self.getLocation(p, 1),
|
||||
doccomments=p.slice[1].doccomments)
|
||||
|
||||
def p_variants_start(self, p):
|
||||
"""variants : """
|
||||
p[0] = []
|
||||
|
||||
def p_variants_single(self, p):
|
||||
"""variants : variant"""
|
||||
p[0] = [p[1]]
|
||||
|
||||
def p_variants_continue(self, p):
|
||||
"""variants : variant ',' variants"""
|
||||
p[0] = [p[1]] + p[3]
|
||||
|
||||
def p_variant_implicit(self, p):
|
||||
"""variant : IDENTIFIER"""
|
||||
p[0] = CEnumVariant(p[1], None, self.getLocation(p, 1))
|
||||
|
||||
def p_variant_explicit(self, p):
|
||||
"""variant : IDENTIFIER '=' number"""
|
||||
p[0] = CEnumVariant(p[1], p[3], self.getLocation(p, 1))
|
||||
|
||||
def p_member_att(self, p):
|
||||
"""member : attributes optreadonly ATTRIBUTE type IDENTIFIER ';'"""
|
||||
if 'doccomments' in p[1]:
|
||||
|
|
Загрузка…
Ссылка в новой задаче