]> git.proxmox.com Git - mirror_qemu.git/blame - scripts/qapi/common.py
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging
[mirror_qemu.git] / scripts / qapi / common.py
CommitLineData
0f923be2
MR
1#
2# QAPI helper library
3#
4# Copyright IBM, Corp. 2011
47a6ea9a 5# Copyright (c) 2013-2018 Red Hat Inc.
0f923be2
MR
6#
7# Authors:
8# Anthony Liguori <aliguori@us.ibm.com>
c7a3f252 9# Markus Armbruster <armbru@redhat.com>
0f923be2 10#
678e48a2
MA
11# This work is licensed under the terms of the GNU GPL, version 2.
12# See the COPYING file in the top-level directory.
0f923be2 13
c2613949 14import re
6cc2e481 15from typing import (
5d83b9a1
MAL
16 Any,
17 Dict,
6cc2e481
MAL
18 Match,
19 Optional,
ccea6a86 20 Sequence,
6cc2e481
MAL
21 Union,
22)
0f923be2 23
437db254 24
1cc7398d 25#: Magic string that gets removed along with all space to its right.
a7aa64a6
JS
26EATSPACE = '\033EATSPACE.'
27POINTER_SUFFIX = ' *' + EATSPACE
a7aa64a6
JS
28
29
d646b2a1 30def camel_to_upper(value: str) -> str:
1cc7398d
JS
31 """
32 Converts CamelCase to CAMEL_CASE.
33
34 Examples::
35
36 ENUMName -> ENUM_NAME
37 EnumName1 -> ENUM_NAME1
38 ENUM_NAME -> ENUM_NAME
39 ENUM_NAME1 -> ENUM_NAME1
40 ENUM_Name2 -> ENUM_NAME2
41 ENUM24_Name -> ENUM24_NAME
42 """
849bc538
MA
43 c_fun_str = c_name(value, False)
44 if value.isupper():
45 return c_fun_str
46
47 new_name = ''
b736e25a
MA
48 length = len(c_fun_str)
49 for i in range(length):
73951712
JS
50 char = c_fun_str[i]
51 # When char is upper case and no '_' appears before, do more checks
52 if char.isupper() and (i > 0) and c_fun_str[i - 1] != '_':
b736e25a 53 if i < length - 1 and c_fun_str[i + 1].islower():
437db254
EB
54 new_name += '_'
55 elif c_fun_str[i - 1].isdigit():
849bc538 56 new_name += '_'
73951712 57 new_name += char
849bc538
MA
58 return new_name.lstrip('_').upper()
59
437db254 60
d646b2a1
JS
61def c_enum_const(type_name: str,
62 const_name: str,
63 prefix: Optional[str] = None) -> str:
1cc7398d
JS
64 """
65 Generate a C enumeration constant name.
66
67 :param type_name: The name of the enumeration.
68 :param const_name: The name of this constant.
69 :param prefix: Optional, prefix that overrides the type_name.
70 """
351d36e4
DB
71 if prefix is not None:
72 type_name = prefix
d20a580b 73 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
849bc538 74
b736e25a 75
d646b2a1 76def c_name(name: str, protect: bool = True) -> str:
1cc7398d
JS
77 """
78 Map ``name`` to a valid C identifier.
79
80 Used for converting 'name' from a 'name':'type' qapi definition
81 into a generated struct member, as well as converting type names
82 into substrings of a generated C function name.
83
84 '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
85 protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
86
87 :param name: The name to map.
88 :param protect: If true, avoid returning certain ticklish identifiers
89 (like C keywords) by prepending ``q_``.
90 """
427a1a2c
BS
91 # ANSI X3J11/88-090, 3.1.1
92 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
437db254
EB
93 'default', 'do', 'double', 'else', 'enum', 'extern',
94 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
95 'return', 'short', 'signed', 'sizeof', 'static',
96 'struct', 'switch', 'typedef', 'union', 'unsigned',
97 'void', 'volatile', 'while'])
427a1a2c
BS
98 # ISO/IEC 9899:1999, 6.4.1
99 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
100 # ISO/IEC 9899:2011, 6.4.1
437db254
EB
101 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
102 '_Noreturn', '_Static_assert', '_Thread_local'])
427a1a2c
BS
103 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
104 # excluding _.*
105 gcc_words = set(['asm', 'typeof'])
6f88009e
TS
106 # C++ ISO/IEC 14882:2003 2.11
107 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
108 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
109 'namespace', 'new', 'operator', 'private', 'protected',
110 'public', 'reinterpret_cast', 'static_cast', 'template',
111 'this', 'throw', 'true', 'try', 'typeid', 'typename',
112 'using', 'virtual', 'wchar_t',
113 # alternative representations
114 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
115 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1057725f 116 # namespace pollution:
fd89c8ab 117 polluted_words = set(['unix', 'errno', 'mips', 'sparc', 'i386', 'linux'])
5fbc78dd
MA
118 name = re.sub(r'[^A-Za-z0-9_]', '_', name)
119 if protect and (name in (c89_words | c99_words | c11_words | gcc_words
120 | cpp_words | polluted_words)
121 or name[0].isdigit()):
ef801a9b 122 return 'q_' + name
c43567c1 123 return name
0f923be2 124
b736e25a 125
cbe8f87f
JS
126class Indentation:
127 """
128 Indentation level management.
0f923be2 129
cbe8f87f
JS
130 :param initial: Initial number of spaces, default 0.
131 """
132 def __init__(self, initial: int = 0) -> None:
133 self._level = initial
b736e25a 134
cbe8f87f
JS
135 def __repr__(self) -> str:
136 return "{}({:d})".format(type(self).__name__, self._level)
437db254 137
cbe8f87f
JS
138 def __str__(self) -> str:
139 """Return the current indentation as a string of spaces."""
140 return ' ' * self._level
0f923be2 141
cbe8f87f
JS
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."""
e2ff14a5 148 assert amount <= self._level
cbe8f87f
JS
149 self._level -= amount
150
151
1cc7398d 152#: Global, current indent level for code generation.
cbe8f87f 153indent = Indentation()
0f923be2 154
437db254 155
d646b2a1 156def cgen(code: str, **kwds: object) -> str:
1cc7398d
JS
157 """
158 Generate ``code`` with ``kwds`` interpolated.
159
160 Obey `indent`, and strip `EATSPACE`.
161 """
77e703b8 162 raw = code % kwds
916fca17
MA
163 pfx = str(indent)
164 if pfx:
165 raw = re.sub(r'^(?!(#|$))', pfx, raw, flags=re.MULTILINE)
a7aa64a6 166 return re.sub(re.escape(EATSPACE) + r' *', '', raw)
0f923be2 167
437db254 168
d646b2a1 169def mcgen(code: str, **kwds: object) -> str:
77e703b8
MA
170 if code[0] == '\n':
171 code = code[1:]
172 return cgen(code, **kwds)
0f923be2 173
0f923be2 174
d646b2a1 175def c_fname(filename: str) -> str:
709395f8 176 return re.sub(r'[^A-Za-z0-9_]', '_', filename)
c0afa9c5 177
437db254 178
d646b2a1 179def guardstart(name: str) -> str:
c0afa9c5 180 return mcgen('''
c0afa9c5
MR
181#ifndef %(name)s
182#define %(name)s
183
184''',
709395f8 185 name=c_fname(name).upper())
c0afa9c5 186
437db254 187
d646b2a1 188def guardend(name: str) -> str:
c0afa9c5
MR
189 return mcgen('''
190
191#endif /* %(name)s */
c0afa9c5 192''',
709395f8 193 name=c_fname(name).upper())
2114f5a9 194
437db254 195
ccea6a86
MA
196def gen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]],
197 cond_fmt: str, not_fmt: str,
198 all_operator: str, any_operator: str) -> str:
199
7b275cdd
MA
200 def do_gen(ifcond: Union[str, Dict[str, Any]],
201 need_parens: bool) -> str:
ccea6a86
MA
202 if isinstance(ifcond, str):
203 return cond_fmt % ifcond
204 assert isinstance(ifcond, dict) and len(ifcond) == 1
205 if 'not' in ifcond:
a7987799 206 return not_fmt % do_gen(ifcond['not'], True)
ccea6a86
MA
207 if 'all' in ifcond:
208 gen = gen_infix(all_operator, ifcond['all'])
209 else:
210 gen = gen_infix(any_operator, ifcond['any'])
a7987799
MA
211 if need_parens:
212 gen = '(' + gen + ')'
ccea6a86
MA
213 return gen
214
215 def gen_infix(operator: str, operands: Sequence[Any]) -> str:
a7987799 216 return operator.join([do_gen(o, True) for o in operands])
ccea6a86 217
6cc2e481
MAL
218 if not ifcond:
219 return ''
a7987799 220 return do_gen(ifcond, False)
6cc2e481 221
ccea6a86
MA
222
223def cgen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]]) -> str:
224 return gen_ifcond(ifcond, 'defined(%s)', '!%s', ' && ', ' || ')
6cc2e481 225
5d83b9a1 226
e46c930c 227def docgen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]]) -> str:
d806f89f 228 # TODO Doc generated for conditions needs polish
d0830ee4 229 return gen_ifcond(ifcond, '%s', 'not %s', ' and ', ' or ')
d806f89f
MAL
230
231
6cc2e481
MAL
232def gen_if(cond: str) -> str:
233 if not cond:
234 return ''
235 return mcgen('''
ded9fc28 236#if %(cond)s
6cc2e481 237''', cond=cond)
ded9fc28
MAL
238
239
6cc2e481
MAL
240def gen_endif(cond: str) -> str:
241 if not cond:
242 return ''
243 return mcgen('''
ded9fc28 244#endif /* %(cond)s */
6cc2e481 245''', cond=cond)
e0e8a0ac
JS
246
247
248def must_match(pattern: str, string: str) -> Match[str]:
249 match = re.match(pattern, string)
250 assert match is not None
251 return match