blob: 11b86beeabe6337ef2e35e78d1a1ac7363175651 [file] [log] [blame]
Michael Roth0f923be2011-07-19 14:50:39 -05001#
2# QAPI helper library
3#
4# Copyright IBM, Corp. 2011
Markus Armbruster47a6ea92018-02-26 13:19:40 -06005# Copyright (c) 2013-2018 Red Hat Inc.
Michael Roth0f923be2011-07-19 14:50:39 -05006#
7# Authors:
8# Anthony Liguori <aliguori@us.ibm.com>
Markus Armbrusterc7a3f252013-07-27 17:41:55 +02009# Markus Armbruster <armbru@redhat.com>
Michael Roth0f923be2011-07-19 14:50:39 -050010#
Markus Armbruster678e48a2014-03-01 08:40:34 +010011# This work is licensed under the terms of the GNU GPL, version 2.
12# See the COPYING file in the top-level directory.
Michael Roth0f923be2011-07-19 14:50:39 -050013
Markus Armbrusterc2613942017-03-15 13:57:35 +010014import re
John Snowd646b2a2020-10-09 12:15:37 -040015from typing import Optional, Sequence
Michael Roth0f923be2011-07-19 14:50:39 -050016
Eric Blake437db252015-09-29 16:21:02 -060017
John Snow1cc73982020-10-09 12:15:38 -040018#: Magic string that gets removed along with all space to its right.
John Snowa7aa64a2020-10-09 12:15:34 -040019EATSPACE = '\033EATSPACE.'
20POINTER_SUFFIX = ' *' + EATSPACE
21_C_NAME_TRANS = str.maketrans('.-', '__')
22
23
John Snowd646b2a2020-10-09 12:15:37 -040024def camel_to_upper(value: str) -> str:
John Snow1cc73982020-10-09 12:15:38 -040025 """
26 Converts CamelCase to CAMEL_CASE.
27
28 Examples::
29
30 ENUMName -> ENUM_NAME
31 EnumName1 -> ENUM_NAME1
32 ENUM_NAME -> ENUM_NAME
33 ENUM_NAME1 -> ENUM_NAME1
34 ENUM_Name2 -> ENUM_NAME2
35 ENUM24_Name -> ENUM24_NAME
36 """
Markus Armbruster849bc532015-05-14 06:50:53 -060037 c_fun_str = c_name(value, False)
38 if value.isupper():
39 return c_fun_str
40
41 new_name = ''
Markus Armbrusterb736e252018-06-21 10:35:51 +020042 length = len(c_fun_str)
43 for i in range(length):
John Snow73951712020-10-09 12:15:35 -040044 char = c_fun_str[i]
45 # When char is upper case and no '_' appears before, do more checks
46 if char.isupper() and (i > 0) and c_fun_str[i - 1] != '_':
Markus Armbrusterb736e252018-06-21 10:35:51 +020047 if i < length - 1 and c_fun_str[i + 1].islower():
Eric Blake437db252015-09-29 16:21:02 -060048 new_name += '_'
49 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -060050 new_name += '_'
John Snow73951712020-10-09 12:15:35 -040051 new_name += char
Markus Armbruster849bc532015-05-14 06:50:53 -060052 return new_name.lstrip('_').upper()
53
Eric Blake437db252015-09-29 16:21:02 -060054
John Snowd646b2a2020-10-09 12:15:37 -040055def c_enum_const(type_name: str,
56 const_name: str,
57 prefix: Optional[str] = None) -> str:
John Snow1cc73982020-10-09 12:15:38 -040058 """
59 Generate a C enumeration constant name.
60
61 :param type_name: The name of the enumeration.
62 :param const_name: The name of this constant.
63 :param prefix: Optional, prefix that overrides the type_name.
64 """
Daniel P. Berrange351d36e2015-08-26 14:21:20 +010065 if prefix is not None:
66 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -070067 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -060068
Markus Armbrusterb736e252018-06-21 10:35:51 +020069
John Snowd646b2a2020-10-09 12:15:37 -040070def c_name(name: str, protect: bool = True) -> str:
John Snow1cc73982020-10-09 12:15:38 -040071 """
72 Map ``name`` to a valid C identifier.
73
74 Used for converting 'name' from a 'name':'type' qapi definition
75 into a generated struct member, as well as converting type names
76 into substrings of a generated C function name.
77
78 '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
79 protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
80
81 :param name: The name to map.
82 :param protect: If true, avoid returning certain ticklish identifiers
83 (like C keywords) by prepending ``q_``.
84 """
Blue Swirl427a1a22012-07-30 15:46:55 +000085 # ANSI X3J11/88-090, 3.1.1
86 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -060087 'default', 'do', 'double', 'else', 'enum', 'extern',
88 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
89 'return', 'short', 'signed', 'sizeof', 'static',
90 'struct', 'switch', 'typedef', 'union', 'unsigned',
91 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +000092 # ISO/IEC 9899:1999, 6.4.1
93 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
94 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -060095 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
96 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +000097 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
98 # excluding _.*
99 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -0400100 # C++ ISO/IEC 14882:2003 2.11
101 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
102 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
103 'namespace', 'new', 'operator', 'private', 'protected',
104 'public', 'reinterpret_cast', 'static_cast', 'template',
105 'this', 'throw', 'true', 'try', 'typeid', 'typename',
106 'using', 'virtual', 'wchar_t',
107 # alternative representations
108 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
109 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +0200110 # namespace pollution:
Laszlo Ersek9a801c72018-04-27 21:28:49 +0200111 polluted_words = set(['unix', 'errno', 'mips', 'sparc', 'i386'])
John Snowa7aa64a2020-10-09 12:15:34 -0400112 name = name.translate(_C_NAME_TRANS)
Eric Blake437db252015-09-29 16:21:02 -0600113 if protect and (name in c89_words | c99_words | c11_words | gcc_words
114 | cpp_words | polluted_words):
Markus Armbrusteref801a92017-03-15 13:57:08 +0100115 return 'q_' + name
Eric Blakec43567c2015-11-18 01:52:52 -0700116 return name
Michael Roth0f923be2011-07-19 14:50:39 -0500117
Markus Armbrusterb736e252018-06-21 10:35:51 +0200118
John Snowcbe8f872020-10-09 12:15:33 -0400119class Indentation:
120 """
121 Indentation level management.
122
123 :param initial: Initial number of spaces, default 0.
124 """
125 def __init__(self, initial: int = 0) -> None:
126 self._level = initial
127
128 def __int__(self) -> int:
129 return self._level
130
131 def __repr__(self) -> str:
132 return "{}({:d})".format(type(self).__name__, self._level)
133
134 def __str__(self) -> str:
135 """Return the current indentation as a string of spaces."""
136 return ' ' * self._level
137
138 def __bool__(self) -> bool:
139 """True when there is a non-zero indentation."""
140 return bool(self._level)
141
142 def increase(self, amount: int = 4) -> None:
143 """Increase the indentation level by ``amount``, default 4."""
144 self._level += amount
145
146 def decrease(self, amount: int = 4) -> None:
147 """Decrease the indentation level by ``amount``, default 4."""
148 if self._level < amount:
149 raise ArithmeticError(
150 f"Can't remove {amount:d} spaces from {self!r}")
151 self._level -= amount
Michael Roth0f923be2011-07-19 14:50:39 -0500152
Markus Armbrusterb736e252018-06-21 10:35:51 +0200153
John Snow1cc73982020-10-09 12:15:38 -0400154#: Global, current indent level for code generation.
John Snowcbe8f872020-10-09 12:15:33 -0400155indent = Indentation()
Michael Roth0f923be2011-07-19 14:50:39 -0500156
Eric Blake437db252015-09-29 16:21:02 -0600157
John Snowd646b2a2020-10-09 12:15:37 -0400158def cgen(code: str, **kwds: object) -> str:
John Snow1cc73982020-10-09 12:15:38 -0400159 """
160 Generate ``code`` with ``kwds`` interpolated.
161
162 Obey `indent`, and strip `EATSPACE`.
163 """
Markus Armbruster77e703b2015-06-24 19:27:32 +0200164 raw = code % kwds
John Snowcbe8f872020-10-09 12:15:33 -0400165 if indent:
166 raw = re.sub(r'^(?!(#|$))', str(indent), raw, flags=re.MULTILINE)
John Snowa7aa64a2020-10-09 12:15:34 -0400167 return re.sub(re.escape(EATSPACE) + r' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -0500168
Eric Blake437db252015-09-29 16:21:02 -0600169
John Snowd646b2a2020-10-09 12:15:37 -0400170def mcgen(code: str, **kwds: object) -> str:
Markus Armbruster77e703b2015-06-24 19:27:32 +0200171 if code[0] == '\n':
172 code = code[1:]
173 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -0500174
Michael Roth0f923be2011-07-19 14:50:39 -0500175
John Snowd646b2a2020-10-09 12:15:37 -0400176def c_fname(filename: str) -> str:
Markus Armbruster709395f2019-03-01 16:40:48 +0100177 return re.sub(r'[^A-Za-z0-9_]', '_', filename)
Michael Rothc0afa9c2013-05-10 17:46:00 -0500178
Eric Blake437db252015-09-29 16:21:02 -0600179
John Snowd646b2a2020-10-09 12:15:37 -0400180def guardstart(name: str) -> str:
Michael Rothc0afa9c2013-05-10 17:46:00 -0500181 return mcgen('''
Michael Rothc0afa9c2013-05-10 17:46:00 -0500182#ifndef %(name)s
183#define %(name)s
184
185''',
Markus Armbruster709395f2019-03-01 16:40:48 +0100186 name=c_fname(name).upper())
Michael Rothc0afa9c2013-05-10 17:46:00 -0500187
Eric Blake437db252015-09-29 16:21:02 -0600188
John Snowd646b2a2020-10-09 12:15:37 -0400189def guardend(name: str) -> str:
Michael Rothc0afa9c2013-05-10 17:46:00 -0500190 return mcgen('''
191
192#endif /* %(name)s */
Michael Rothc0afa9c2013-05-10 17:46:00 -0500193''',
Markus Armbruster709395f2019-03-01 16:40:48 +0100194 name=c_fname(name).upper())
Markus Armbruster2114f5a2015-04-02 13:12:21 +0200195
Eric Blake437db252015-09-29 16:21:02 -0600196
John Snowd646b2a2020-10-09 12:15:37 -0400197def gen_if(ifcond: Sequence[str]) -> str:
Marc-André Lureauded9fc22018-07-03 17:56:40 +0200198 ret = ''
199 for ifc in ifcond:
200 ret += mcgen('''
201#if %(cond)s
202''', cond=ifc)
203 return ret
204
205
John Snowd646b2a2020-10-09 12:15:37 -0400206def gen_endif(ifcond: Sequence[str]) -> str:
Marc-André Lureauded9fc22018-07-03 17:56:40 +0200207 ret = ''
208 for ifc in reversed(ifcond):
209 ret += mcgen('''
210#endif /* %(cond)s */
211''', cond=ifc)
212 return ret