qapi: Make c_type() consistently convert qapi names

Continuing the string of cleanups for supporting downstream names
containing '.', this patch focuses on ensuring c_type() can
handle a downstream name. This patch alone does not fix the
places where generator output should be calling this function
but was open-coding things instead, but it gets us a step closer.

In particular, the changes to c_list_type() and type_name() mean
that type_name(FOO) now handles the case when FOO contains '.',
'-', or is a ticklish identifier other than a builtin (builtins
are exempted because ['int'] must remain mapped to 'intList' and
not 'q_intList'). Meanwhile, ['unix'] now maps to 'q_unixList'
rather than 'unixList', to match the fact that 'unix' is ticklish;
however, our naming conventions state that complex types should
start with a capital, so no type name following conventions will
ever have the 'q_' prepended.

Likewise, changes to c_type() mean that c_type(FOO) properly
handles an enum or complex type FOO with '.' or '-' in the
name, or is a ticklish identifier (again, a ticklish identifier
as a type name violates conventions).

Backports commit c6405b54b7b09a876f2f2fba2aa6f8ac87189cb9 from qemu
This commit is contained in:
Eric Blake 2018-02-19 14:56:46 -05:00 committed by Lioncash
parent 7ec0edc6c6
commit 2045cd0ada
No known key found for this signature in database
GPG Key ID: 4E3C3CC1031BA9C7

View File

@ -779,6 +779,15 @@ def c_enum_const(type_name, const_name):
c_name_trans = string.maketrans('.-', '__') c_name_trans = string.maketrans('.-', '__')
# Map @name to a valid C identifier.
# If @protect, avoid returning certain ticklish identifiers (like
# C keywords) by prepending "q_".
#
# Used for converting 'name' from a 'name':'type' qapi definition
# into a generated struct member, as well as converting type names
# into substrings of a generated C function name.
# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
def c_name(name, protect=True): def c_name(name, protect=True):
# ANSI X3J11/88-090, 3.1.1 # ANSI X3J11/88-090, 3.1.1
c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue', c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
@ -810,13 +819,25 @@ def c_name(name, protect=True):
return "q_" + name return "q_" + name
return name.translate(c_name_trans) return name.translate(c_name_trans)
# Map type @name to the C typedef name for the list form.
#
# ['Name'] -> 'NameList', ['x-Foo'] -> 'x_FooList', ['int'] -> 'intList'
def c_list_type(name): def c_list_type(name):
return name + 'List' return name + 'List'
# Map type @value to the C typedef form.
#
# Used for converting 'type' from a 'member':'type' qapi definition
# into the alphanumeric portion of the type for a generated C parameter,
# as well as generated C function names. See c_type() for the rest of
# the conversion such as adding '*' on pointer types.
# 'int' -> 'int', '[x-Foo]' -> 'x_FooList', '__a.b_c' -> '__a_b_c'
def type_name(value): def type_name(value):
if type(value) == list: if type(value) == list:
return c_list_type(value[0]) return c_list_type(value[0])
if value in builtin_types.keys():
return value return value
return c_name(value)
def add_name(name, info, meta, implicit = False): def add_name(name, info, meta, implicit = False):
global all_names global all_names
@ -875,6 +896,10 @@ def is_enum(name):
eatspace = '\033EATSPACE.' eatspace = '\033EATSPACE.'
pointer_suffix = ' *' + eatspace pointer_suffix = ' *' + eatspace
# Map type @name to its C type expression.
# If @is_param, const-qualify the string type.
#
# This function is used for computing the full C type of 'member':'name'.
# A special suffix is added in c_type() for pointer types, and it's # A special suffix is added in c_type() for pointer types, and it's
# stripped in mcgen(). So please notice this when you check the return # stripped in mcgen(). So please notice this when you check the return
# value of c_type() outside mcgen(). # value of c_type() outside mcgen().
@ -899,7 +924,7 @@ def c_type(value, is_param=False):
elif type(value) == list: elif type(value) == list:
return c_list_type(value[0]) + pointer_suffix return c_list_type(value[0]) + pointer_suffix
elif is_enum(value): elif is_enum(value):
return value return c_name(value)
elif value == None: elif value == None:
return 'void' return 'void'
elif value in events: elif value in events:
@ -907,7 +932,7 @@ def c_type(value, is_param=False):
else: else:
# complex type name # complex type name
assert isinstance(value, str) and value != "" assert isinstance(value, str) and value != ""
return value + pointer_suffix return c_name(value) + pointer_suffix
def is_c_ptr(value): def is_c_ptr(value):
return c_type(value).endswith(pointer_suffix) return c_type(value).endswith(pointer_suffix)