]> git.proxmox.com Git - mirror_qemu.git/blame - scripts/qapi.py
qapi: Improve a couple of confusing variable names
[mirror_qemu.git] / scripts / qapi.py
CommitLineData
0f923be2
MR
1#
2# QAPI helper library
3#
4# Copyright IBM, Corp. 2011
fe2a9303 5# Copyright (c) 2013-2015 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
a719a27c 14import re
0f923be2 15from ordereddict import OrderedDict
12f8e1b9 16import errno
2114f5a9 17import getopt
33aaad52 18import os
2caba36c 19import sys
47299262 20import string
0f923be2 21
b52c4b9c 22builtin_types = {
69dd62df
KW
23 'str': 'QTYPE_QSTRING',
24 'int': 'QTYPE_QINT',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
27 'int8': 'QTYPE_QINT',
28 'int16': 'QTYPE_QINT',
29 'int32': 'QTYPE_QINT',
30 'int64': 'QTYPE_QINT',
31 'uint8': 'QTYPE_QINT',
32 'uint16': 'QTYPE_QINT',
33 'uint32': 'QTYPE_QINT',
34 'uint64': 'QTYPE_QINT',
cb17f79e 35 'size': 'QTYPE_QINT',
69dd62df
KW
36}
37
10d4d997
EB
38# Whitelist of commands allowed to return a non-dictionary
39returns_whitelist = [
40 # From QMP:
41 'human-monitor-command',
42 'query-migrate-cache-size',
43 'query-tpm-models',
44 'query-tpm-types',
45 'ringbuf-read',
46
47 # From QGA:
48 'guest-file-open',
49 'guest-fsfreeze-freeze',
50 'guest-fsfreeze-freeze-list',
51 'guest-fsfreeze-status',
52 'guest-fsfreeze-thaw',
53 'guest-get-time',
54 'guest-set-vcpus',
55 'guest-sync',
56 'guest-sync-delimited',
57
58 # From qapi-schema-test:
59 'user_def_cmd3',
60]
61
4dc2e690
EB
62enum_types = []
63struct_types = []
64union_types = []
65events = []
66all_names = {}
67
a719a27c
LV
68def error_path(parent):
69 res = ""
70 while parent:
71 res = ("In file included from %s:%d:\n" % (parent['file'],
72 parent['line'])) + res
73 parent = parent['parent']
74 return res
75
2caba36c
MA
76class QAPISchemaError(Exception):
77 def __init__(self, schema, msg):
54414047 78 self.fname = schema.fname
2caba36c 79 self.msg = msg
515b943a
WX
80 self.col = 1
81 self.line = schema.line
82 for ch in schema.src[schema.line_pos:schema.pos]:
83 if ch == '\t':
2caba36c
MA
84 self.col = (self.col + 7) % 8 + 1
85 else:
86 self.col += 1
54414047 87 self.info = schema.incl_info
2caba36c
MA
88
89 def __str__(self):
a719a27c 90 return error_path(self.info) + \
54414047 91 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
2caba36c 92
b86b05ed
WX
93class QAPIExprError(Exception):
94 def __init__(self, expr_info, msg):
a719a27c 95 self.info = expr_info
b86b05ed
WX
96 self.msg = msg
97
98 def __str__(self):
a719a27c
LV
99 return error_path(self.info['parent']) + \
100 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
b86b05ed 101
c7a3f252
MA
102class QAPISchema:
103
54414047
MA
104 def __init__(self, fp, fname = None, include_hist = [],
105 previously_included = [], incl_info = None):
24fd8489
BC
106 """ include_hist is a stack used to detect inclusion cycles
107 previously_included is a global state used to avoid multiple
108 inclusions of the same file"""
54414047
MA
109 abs_fname = os.path.abspath(fp.name)
110 if fname is None:
111 fname = fp.name
112 self.fname = fname
113 self.include_hist = include_hist + [(fname, abs_fname)]
114 previously_included.append(abs_fname)
115 self.incl_info = incl_info
c7a3f252
MA
116 self.src = fp.read()
117 if self.src == '' or self.src[-1] != '\n':
118 self.src += '\n'
119 self.cursor = 0
515b943a
WX
120 self.line = 1
121 self.line_pos = 0
c7a3f252
MA
122 self.exprs = []
123 self.accept()
124
125 while self.tok != None:
54414047
MA
126 expr_info = {'file': fname, 'line': self.line,
127 'parent': self.incl_info}
a719a27c
LV
128 expr = self.get_expr(False)
129 if isinstance(expr, dict) and "include" in expr:
130 if len(expr) != 1:
131 raise QAPIExprError(expr_info, "Invalid 'include' directive")
132 include = expr["include"]
133 if not isinstance(include, str):
134 raise QAPIExprError(expr_info,
135 'Expected a file name (string), got: %s'
136 % include)
54414047
MA
137 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
138 include)
7ac9a9d6 139 for elem in self.include_hist:
54414047 140 if incl_abs_fname == elem[1]:
7ac9a9d6
SH
141 raise QAPIExprError(expr_info, "Inclusion loop for %s"
142 % include)
24fd8489 143 # skip multiple include of the same file
54414047 144 if incl_abs_fname in previously_included:
24fd8489 145 continue
a719a27c 146 try:
54414047 147 fobj = open(incl_abs_fname, 'r')
34788811 148 except IOError, e:
a719a27c
LV
149 raise QAPIExprError(expr_info,
150 '%s: %s' % (e.strerror, include))
24fd8489
BC
151 exprs_include = QAPISchema(fobj, include, self.include_hist,
152 previously_included, expr_info)
a719a27c
LV
153 self.exprs.extend(exprs_include.exprs)
154 else:
155 expr_elem = {'expr': expr,
156 'info': expr_info}
157 self.exprs.append(expr_elem)
c7a3f252
MA
158
159 def accept(self):
160 while True:
c7a3f252 161 self.tok = self.src[self.cursor]
2caba36c 162 self.pos = self.cursor
c7a3f252
MA
163 self.cursor += 1
164 self.val = None
165
f1a145e1 166 if self.tok == '#':
c7a3f252
MA
167 self.cursor = self.src.find('\n', self.cursor)
168 elif self.tok in ['{', '}', ':', ',', '[', ']']:
169 return
170 elif self.tok == "'":
171 string = ''
172 esc = False
173 while True:
174 ch = self.src[self.cursor]
175 self.cursor += 1
176 if ch == '\n':
2caba36c
MA
177 raise QAPISchemaError(self,
178 'Missing terminating "\'"')
c7a3f252 179 if esc:
a7f5966b
EB
180 if ch == 'b':
181 string += '\b'
182 elif ch == 'f':
183 string += '\f'
184 elif ch == 'n':
185 string += '\n'
186 elif ch == 'r':
187 string += '\r'
188 elif ch == 't':
189 string += '\t'
190 elif ch == 'u':
191 value = 0
192 for x in range(0, 4):
193 ch = self.src[self.cursor]
194 self.cursor += 1
195 if ch not in "0123456789abcdefABCDEF":
196 raise QAPISchemaError(self,
197 '\\u escape needs 4 '
198 'hex digits')
199 value = (value << 4) + int(ch, 16)
200 # If Python 2 and 3 didn't disagree so much on
201 # how to handle Unicode, then we could allow
202 # Unicode string defaults. But most of QAPI is
203 # ASCII-only, so we aren't losing much for now.
204 if not value or value > 0x7f:
205 raise QAPISchemaError(self,
206 'For now, \\u escape '
207 'only supports non-zero '
208 'values up to \\u007f')
209 string += chr(value)
210 elif ch in "\\/'\"":
211 string += ch
212 else:
213 raise QAPISchemaError(self,
214 "Unknown escape \\%s" %ch)
c7a3f252
MA
215 esc = False
216 elif ch == "\\":
217 esc = True
218 elif ch == "'":
219 self.val = string
220 return
221 else:
222 string += ch
e53188ad
FZ
223 elif self.tok in "tfn":
224 val = self.src[self.cursor - 1:]
225 if val.startswith("true"):
226 self.val = True
227 self.cursor += 3
228 return
229 elif val.startswith("false"):
230 self.val = False
231 self.cursor += 4
232 return
233 elif val.startswith("null"):
234 self.val = None
235 self.cursor += 3
236 return
c7a3f252
MA
237 elif self.tok == '\n':
238 if self.cursor == len(self.src):
239 self.tok = None
240 return
515b943a
WX
241 self.line += 1
242 self.line_pos = self.cursor
9213aa53
MA
243 elif not self.tok.isspace():
244 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
c7a3f252
MA
245
246 def get_members(self):
247 expr = OrderedDict()
6974ccd5
MA
248 if self.tok == '}':
249 self.accept()
250 return expr
251 if self.tok != "'":
252 raise QAPISchemaError(self, 'Expected string or "}"')
253 while True:
c7a3f252
MA
254 key = self.val
255 self.accept()
6974ccd5
MA
256 if self.tok != ':':
257 raise QAPISchemaError(self, 'Expected ":"')
258 self.accept()
4b35991a
WX
259 if key in expr:
260 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
5f3cd2b7 261 expr[key] = self.get_expr(True)
6974ccd5 262 if self.tok == '}':
c7a3f252 263 self.accept()
6974ccd5
MA
264 return expr
265 if self.tok != ',':
266 raise QAPISchemaError(self, 'Expected "," or "}"')
267 self.accept()
268 if self.tok != "'":
269 raise QAPISchemaError(self, 'Expected string')
c7a3f252
MA
270
271 def get_values(self):
272 expr = []
6974ccd5
MA
273 if self.tok == ']':
274 self.accept()
275 return expr
e53188ad
FZ
276 if not self.tok in "{['tfn":
277 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
278 'boolean or "null"')
6974ccd5 279 while True:
5f3cd2b7 280 expr.append(self.get_expr(True))
6974ccd5 281 if self.tok == ']':
c7a3f252 282 self.accept()
6974ccd5
MA
283 return expr
284 if self.tok != ',':
285 raise QAPISchemaError(self, 'Expected "," or "]"')
286 self.accept()
c7a3f252 287
5f3cd2b7
MA
288 def get_expr(self, nested):
289 if self.tok != '{' and not nested:
290 raise QAPISchemaError(self, 'Expected "{"')
c7a3f252
MA
291 if self.tok == '{':
292 self.accept()
293 expr = self.get_members()
294 elif self.tok == '[':
295 self.accept()
296 expr = self.get_values()
e53188ad 297 elif self.tok in "'tfn":
c7a3f252
MA
298 expr = self.val
299 self.accept()
6974ccd5
MA
300 else:
301 raise QAPISchemaError(self, 'Expected "{", "[" or string')
c7a3f252 302 return expr
bd9927fe 303
b86b05ed
WX
304def find_base_fields(base):
305 base_struct_define = find_struct(base)
306 if not base_struct_define:
307 return None
308 return base_struct_define['data']
309
811d04fd
EB
310# Return the qtype of an alternate branch, or None on error.
311def find_alternate_member_qtype(qapi_type):
44bd1276
EB
312 if builtin_types.has_key(qapi_type):
313 return builtin_types[qapi_type]
314 elif find_struct(qapi_type):
315 return "QTYPE_QDICT"
316 elif find_enum(qapi_type):
317 return "QTYPE_QSTRING"
811d04fd
EB
318 elif find_union(qapi_type):
319 return "QTYPE_QDICT"
44bd1276
EB
320 return None
321
bceae769
WX
322# Return the discriminator enum define if discriminator is specified as an
323# enum type, otherwise return None.
324def discriminator_find_enum_define(expr):
325 base = expr.get('base')
326 discriminator = expr.get('discriminator')
327
328 if not (discriminator and base):
329 return None
330
331 base_fields = find_base_fields(base)
332 if not base_fields:
333 return None
334
335 discriminator_type = base_fields.get(discriminator)
336 if not discriminator_type:
337 return None
338
339 return find_enum(discriminator_type)
340
c9e0a798
EB
341valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$')
342def check_name(expr_info, source, name, allow_optional = False,
343 enum_member = False):
344 global valid_name
345 membername = name
346
347 if not isinstance(name, str):
348 raise QAPIExprError(expr_info,
349 "%s requires a string name" % source)
350 if name.startswith('*'):
351 membername = name[1:]
352 if not allow_optional:
353 raise QAPIExprError(expr_info,
354 "%s does not allow optional name '%s'"
355 % (source, name))
356 # Enum members can start with a digit, because the generated C
357 # code always prefixes it with the enum name
358 if enum_member:
359 membername = '_' + membername
360 if not valid_name.match(membername):
361 raise QAPIExprError(expr_info,
362 "%s uses invalid name '%s'" % (source, name))
363
dd883c6f 364def check_type(expr_info, source, value, allow_array = False,
2cbf0992
EB
365 allow_dict = False, allow_optional = False,
366 allow_star = False, allow_metas = []):
dd883c6f
EB
367 global all_names
368 orig_value = value
369
370 if value is None:
371 return
372
2cbf0992 373 if allow_star and value == '**':
dd883c6f
EB
374 return
375
376 # Check if array type for value is okay
377 if isinstance(value, list):
378 if not allow_array:
379 raise QAPIExprError(expr_info,
380 "%s cannot be an array" % source)
381 if len(value) != 1 or not isinstance(value[0], str):
382 raise QAPIExprError(expr_info,
383 "%s: array type must contain single type name"
384 % source)
385 value = value[0]
386 orig_value = "array of %s" %value
387
388 # Check if type name for value is okay
389 if isinstance(value, str):
2cbf0992
EB
390 if value == '**':
391 raise QAPIExprError(expr_info,
392 "%s uses '**' but did not request 'gen':false"
393 % source)
dd883c6f
EB
394 if not value in all_names:
395 raise QAPIExprError(expr_info,
396 "%s uses unknown type '%s'"
397 % (source, orig_value))
398 if not all_names[value] in allow_metas:
399 raise QAPIExprError(expr_info,
400 "%s cannot use %s type '%s'"
401 % (source, all_names[value], orig_value))
402 return
403
404 # value is a dictionary, check that each member is okay
405 if not isinstance(value, OrderedDict):
406 raise QAPIExprError(expr_info,
407 "%s should be a dictionary" % source)
408 if not allow_dict:
409 raise QAPIExprError(expr_info,
410 "%s should be a type name" % source)
411 for (key, arg) in value.items():
c9e0a798
EB
412 check_name(expr_info, "Member of %s" % source, key,
413 allow_optional=allow_optional)
6b5abc7d
EB
414 # Todo: allow dictionaries to represent default values of
415 # an optional argument.
dd883c6f 416 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
6b5abc7d 417 allow_array=True, allow_star=allow_star,
dd883c6f 418 allow_metas=['built-in', 'union', 'alternate', 'struct',
6b5abc7d 419 'enum'])
dd883c6f 420
ff55d72e
EB
421def check_member_clash(expr_info, base_name, data, source = ""):
422 base = find_struct(base_name)
423 assert base
424 base_members = base['data']
425 for key in data.keys():
426 if key.startswith('*'):
427 key = key[1:]
428 if key in base_members or "*" + key in base_members:
429 raise QAPIExprError(expr_info,
430 "Member name '%s'%s clashes with base '%s'"
431 % (key, source, base_name))
432 if base.get('base'):
433 check_member_clash(expr_info, base['base'], data, source)
434
dd883c6f
EB
435def check_command(expr, expr_info):
436 name = expr['command']
2cbf0992
EB
437 allow_star = expr.has_key('gen')
438
dd883c6f 439 check_type(expr_info, "'data' for command '%s'" % name,
c9e0a798 440 expr.get('data'), allow_dict=True, allow_optional=True,
2cbf0992 441 allow_metas=['union', 'struct'], allow_star=allow_star)
10d4d997
EB
442 returns_meta = ['union', 'struct']
443 if name in returns_whitelist:
444 returns_meta += ['built-in', 'alternate', 'enum']
dd883c6f
EB
445 check_type(expr_info, "'returns' for command '%s'" % name,
446 expr.get('returns'), allow_array=True, allow_dict=True,
2cbf0992
EB
447 allow_optional=True, allow_metas=returns_meta,
448 allow_star=allow_star)
dd883c6f 449
21cd70df 450def check_event(expr, expr_info):
4dc2e690
EB
451 global events
452 name = expr['event']
21cd70df 453 params = expr.get('data')
4dc2e690
EB
454
455 if name.upper() == 'MAX':
456 raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
457 events.append(name)
dd883c6f 458 check_type(expr_info, "'data' for event '%s'" % name,
c9e0a798 459 expr.get('data'), allow_dict=True, allow_optional=True,
dd883c6f 460 allow_metas=['union', 'struct'])
21cd70df 461
b86b05ed
WX
462def check_union(expr, expr_info):
463 name = expr['union']
464 base = expr.get('base')
465 discriminator = expr.get('discriminator')
466 members = expr['data']
44bd1276 467 values = { 'MAX': '(automatic)' }
b86b05ed 468
fd41dd4e 469 # If the object has a member 'base', its value must name a struct,
a8d4a2e4
EB
470 # and there must be a discriminator.
471 if base is not None:
472 if discriminator is None:
473 raise QAPIExprError(expr_info,
474 "Union '%s' requires a discriminator to go "
475 "along with base" %name)
b86b05ed 476
811d04fd 477 # Two types of unions, determined by discriminator.
811d04fd
EB
478
479 # With no discriminator it is a simple union.
480 if discriminator is None:
b86b05ed 481 enum_define = None
dd883c6f 482 allow_metas=['built-in', 'union', 'alternate', 'struct', 'enum']
44bd1276
EB
483 if base is not None:
484 raise QAPIExprError(expr_info,
811d04fd 485 "Simple union '%s' must not have a base"
44bd1276 486 % name)
b86b05ed
WX
487
488 # Else, it's a flat union.
489 else:
44bd1276
EB
490 # The object must have a string member 'base'.
491 if not isinstance(base, str):
b86b05ed 492 raise QAPIExprError(expr_info,
44bd1276 493 "Flat union '%s' must have a string base field"
b86b05ed 494 % name)
44bd1276
EB
495 base_fields = find_base_fields(base)
496 if not base_fields:
497 raise QAPIExprError(expr_info,
fd41dd4e 498 "Base '%s' is not a valid struct"
44bd1276
EB
499 % base)
500
c9e0a798 501 # The value of member 'discriminator' must name a non-optional
fd41dd4e 502 # member of the base struct.
c9e0a798
EB
503 check_name(expr_info, "Discriminator of flat union '%s'" % name,
504 discriminator)
b86b05ed
WX
505 discriminator_type = base_fields.get(discriminator)
506 if not discriminator_type:
507 raise QAPIExprError(expr_info,
508 "Discriminator '%s' is not a member of base "
fd41dd4e 509 "struct '%s'"
b86b05ed
WX
510 % (discriminator, base))
511 enum_define = find_enum(discriminator_type)
dd883c6f 512 allow_metas=['struct']
5223070c
WX
513 # Do not allow string discriminator
514 if not enum_define:
515 raise QAPIExprError(expr_info,
516 "Discriminator '%s' must be of enumeration "
517 "type" % discriminator)
b86b05ed
WX
518
519 # Check every branch
520 for (key, value) in members.items():
c9e0a798
EB
521 check_name(expr_info, "Member of union '%s'" % name, key)
522
dd883c6f 523 # Each value must name a known type; furthermore, in flat unions,
ff55d72e 524 # branches must be a struct with no overlapping member names
dd883c6f
EB
525 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
526 value, allow_array=True, allow_metas=allow_metas)
ff55d72e
EB
527 if base:
528 branch_struct = find_struct(value)
529 assert branch_struct
530 check_member_clash(expr_info, base, branch_struct['data'],
531 " of branch '%s'" % key)
dd883c6f 532
44bd1276 533 # If the discriminator names an enum type, then all members
b86b05ed 534 # of 'data' must also be members of the enum type.
44bd1276
EB
535 if enum_define:
536 if not key in enum_define['enum_values']:
537 raise QAPIExprError(expr_info,
538 "Discriminator value '%s' is not found in "
539 "enum '%s'" %
540 (key, enum_define["enum_name"]))
541
542 # Otherwise, check for conflicts in the generated enum
543 else:
fa6068a1 544 c_key = camel_to_upper(key)
44bd1276
EB
545 if c_key in values:
546 raise QAPIExprError(expr_info,
547 "Union '%s' member '%s' clashes with '%s'"
548 % (name, key, values[c_key]))
549 values[c_key] = key
550
811d04fd 551def check_alternate(expr, expr_info):
ab916fad 552 name = expr['alternate']
811d04fd
EB
553 members = expr['data']
554 values = { 'MAX': '(automatic)' }
555 types_seen = {}
556
811d04fd
EB
557 # Check every branch
558 for (key, value) in members.items():
c9e0a798
EB
559 check_name(expr_info, "Member of alternate '%s'" % name, key)
560
811d04fd 561 # Check for conflicts in the generated enum
fa6068a1 562 c_key = camel_to_upper(key)
811d04fd
EB
563 if c_key in values:
564 raise QAPIExprError(expr_info,
ab916fad
EB
565 "Alternate '%s' member '%s' clashes with '%s'"
566 % (name, key, values[c_key]))
811d04fd 567 values[c_key] = key
44bd1276 568
811d04fd 569 # Ensure alternates have no type conflicts.
dd883c6f
EB
570 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
571 value,
572 allow_metas=['built-in', 'union', 'struct', 'enum'])
811d04fd 573 qtype = find_alternate_member_qtype(value)
dd883c6f 574 assert qtype
811d04fd
EB
575 if qtype in types_seen:
576 raise QAPIExprError(expr_info,
ab916fad 577 "Alternate '%s' member '%s' can't "
811d04fd
EB
578 "be distinguished from member '%s'"
579 % (name, key, types_seen[qtype]))
580 types_seen[qtype] = key
b86b05ed 581
cf393590
EB
582def check_enum(expr, expr_info):
583 name = expr['enum']
584 members = expr.get('data')
585 values = { 'MAX': '(automatic)' }
586
587 if not isinstance(members, list):
588 raise QAPIExprError(expr_info,
589 "Enum '%s' requires an array for 'data'" % name)
590 for member in members:
c9e0a798
EB
591 check_name(expr_info, "Member of enum '%s'" %name, member,
592 enum_member=True)
fa6068a1 593 key = camel_to_upper(member)
cf393590
EB
594 if key in values:
595 raise QAPIExprError(expr_info,
596 "Enum '%s' member '%s' clashes with '%s'"
597 % (name, member, values[key]))
598 values[key] = member
599
dd883c6f 600def check_struct(expr, expr_info):
fd41dd4e 601 name = expr['struct']
dd883c6f
EB
602 members = expr['data']
603
fd41dd4e 604 check_type(expr_info, "'data' for struct '%s'" % name, members,
c9e0a798 605 allow_dict=True, allow_optional=True)
fd41dd4e 606 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
dd883c6f 607 allow_metas=['struct'])
ff55d72e
EB
608 if expr.get('base'):
609 check_member_clash(expr_info, expr['base'], expr['data'])
dd883c6f 610
b86b05ed
WX
611def check_exprs(schema):
612 for expr_elem in schema.exprs:
613 expr = expr_elem['expr']
cf393590
EB
614 info = expr_elem['info']
615
616 if expr.has_key('enum'):
617 check_enum(expr, info)
618 elif expr.has_key('union'):
ab916fad
EB
619 check_union(expr, info)
620 elif expr.has_key('alternate'):
621 check_alternate(expr, info)
fd41dd4e 622 elif expr.has_key('struct'):
dd883c6f
EB
623 check_struct(expr, info)
624 elif expr.has_key('command'):
625 check_command(expr, info)
cf393590
EB
626 elif expr.has_key('event'):
627 check_event(expr, info)
dd883c6f
EB
628 else:
629 assert False, 'unexpected meta type'
b86b05ed 630
0545f6b8
EB
631def check_keys(expr_elem, meta, required, optional=[]):
632 expr = expr_elem['expr']
633 info = expr_elem['info']
634 name = expr[meta]
635 if not isinstance(name, str):
636 raise QAPIExprError(info,
637 "'%s' key must have a string value" % meta)
638 required = required + [ meta ]
639 for (key, value) in expr.items():
640 if not key in required and not key in optional:
641 raise QAPIExprError(info,
642 "Unknown key '%s' in %s '%s'"
643 % (key, meta, name))
2cbf0992
EB
644 if (key == 'gen' or key == 'success-response') and value != False:
645 raise QAPIExprError(info,
646 "'%s' of %s '%s' should only use false value"
647 % (key, meta, name))
0545f6b8
EB
648 for key in required:
649 if not expr.has_key(key):
650 raise QAPIExprError(info,
651 "Key '%s' is missing from %s '%s'"
652 % (key, meta, name))
653
654
54414047 655def parse_schema(fname):
4dc2e690
EB
656 global all_names
657 exprs = []
658
268a1c5e 659 # First pass: read entire file into memory
2caba36c 660 try:
54414047 661 schema = QAPISchema(open(fname, "r"))
a719a27c 662 except (QAPISchemaError, QAPIExprError), e:
2caba36c
MA
663 print >>sys.stderr, e
664 exit(1)
665
b86b05ed 666 try:
0545f6b8
EB
667 # Next pass: learn the types and check for valid expression keys. At
668 # this point, top-level 'include' has already been flattened.
4dc2e690
EB
669 for builtin in builtin_types.keys():
670 all_names[builtin] = 'built-in'
268a1c5e
EB
671 for expr_elem in schema.exprs:
672 expr = expr_elem['expr']
4dc2e690 673 info = expr_elem['info']
268a1c5e 674 if expr.has_key('enum'):
0545f6b8 675 check_keys(expr_elem, 'enum', ['data'])
4dc2e690 676 add_enum(expr['enum'], info, expr['data'])
268a1c5e 677 elif expr.has_key('union'):
0545f6b8
EB
678 check_keys(expr_elem, 'union', ['data'],
679 ['base', 'discriminator'])
4dc2e690 680 add_union(expr, info)
0545f6b8
EB
681 elif expr.has_key('alternate'):
682 check_keys(expr_elem, 'alternate', ['data'])
4dc2e690 683 add_name(expr['alternate'], info, 'alternate')
fd41dd4e
EB
684 elif expr.has_key('struct'):
685 check_keys(expr_elem, 'struct', ['data'], ['base'])
4dc2e690 686 add_struct(expr, info)
0545f6b8
EB
687 elif expr.has_key('command'):
688 check_keys(expr_elem, 'command', [],
689 ['data', 'returns', 'gen', 'success-response'])
4dc2e690 690 add_name(expr['command'], info, 'command')
0545f6b8
EB
691 elif expr.has_key('event'):
692 check_keys(expr_elem, 'event', [], ['data'])
4dc2e690 693 add_name(expr['event'], info, 'event')
0545f6b8
EB
694 else:
695 raise QAPIExprError(expr_elem['info'],
696 "Expression is missing metatype")
268a1c5e
EB
697 exprs.append(expr)
698
699 # Try again for hidden UnionKind enum
700 for expr_elem in schema.exprs:
701 expr = expr_elem['expr']
702 if expr.has_key('union'):
703 if not discriminator_find_enum_define(expr):
4dc2e690
EB
704 add_enum('%sKind' % expr['union'], expr_elem['info'],
705 implicit=True)
ab916fad 706 elif expr.has_key('alternate'):
4dc2e690
EB
707 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
708 implicit=True)
268a1c5e
EB
709
710 # Final pass - validate that exprs make sense
b86b05ed
WX
711 check_exprs(schema)
712 except QAPIExprError, e:
713 print >>sys.stderr, e
714 exit(1)
715
0f923be2
MR
716 return exprs
717
718def parse_args(typeinfo):
fe2a9303 719 if isinstance(typeinfo, str):
b35284ea
KW
720 struct = find_struct(typeinfo)
721 assert struct != None
722 typeinfo = struct['data']
723
0f923be2
MR
724 for member in typeinfo:
725 argname = member
726 argentry = typeinfo[member]
727 optional = False
0f923be2
MR
728 if member.startswith('*'):
729 argname = member[1:]
730 optional = True
6b5abc7d
EB
731 # Todo: allow argentry to be OrderedDict, for providing the
732 # value of an optional argument.
733 yield (argname, argentry, optional)
0f923be2 734
0f923be2
MR
735def camel_case(name):
736 new_name = ''
737 first = True
738 for ch in name:
739 if ch in ['_', '-']:
740 first = True
741 elif first:
742 new_name += ch.upper()
743 first = False
744 else:
745 new_name += ch.lower()
746 return new_name
747
849bc538
MA
748# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
749# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
750# ENUM24_Name -> ENUM24_NAME
751def camel_to_upper(value):
752 c_fun_str = c_name(value, False)
753 if value.isupper():
754 return c_fun_str
755
756 new_name = ''
757 l = len(c_fun_str)
758 for i in range(l):
759 c = c_fun_str[i]
760 # When c is upper and no "_" appears before, do more checks
761 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
762 # Case 1: next string is lower
763 # Case 2: previous string is digit
764 if (i < (l - 1) and c_fun_str[i + 1].islower()) or \
765 c_fun_str[i - 1].isdigit():
766 new_name += '_'
767 new_name += c
768 return new_name.lstrip('_').upper()
769
770def c_enum_const(type_name, const_name):
771 return camel_to_upper(type_name + '_' + const_name)
772
18df515e 773c_name_trans = string.maketrans('.-', '__')
47299262 774
c6405b54
EB
775# Map @name to a valid C identifier.
776# If @protect, avoid returning certain ticklish identifiers (like
777# C keywords) by prepending "q_".
778#
779# Used for converting 'name' from a 'name':'type' qapi definition
780# into a generated struct member, as well as converting type names
781# into substrings of a generated C function name.
782# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
783# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
18df515e 784def c_name(name, protect=True):
427a1a2c
BS
785 # ANSI X3J11/88-090, 3.1.1
786 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
787 'default', 'do', 'double', 'else', 'enum', 'extern', 'float',
788 'for', 'goto', 'if', 'int', 'long', 'register', 'return',
789 'short', 'signed', 'sizeof', 'static', 'struct', 'switch',
790 'typedef', 'union', 'unsigned', 'void', 'volatile', 'while'])
791 # ISO/IEC 9899:1999, 6.4.1
792 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
793 # ISO/IEC 9899:2011, 6.4.1
794 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic', '_Noreturn',
795 '_Static_assert', '_Thread_local'])
796 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
797 # excluding _.*
798 gcc_words = set(['asm', 'typeof'])
6f88009e
TS
799 # C++ ISO/IEC 14882:2003 2.11
800 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
801 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
802 'namespace', 'new', 'operator', 'private', 'protected',
803 'public', 'reinterpret_cast', 'static_cast', 'template',
804 'this', 'throw', 'true', 'try', 'typeid', 'typename',
805 'using', 'virtual', 'wchar_t',
806 # alternative representations
807 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
808 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1057725f 809 # namespace pollution:
8592a545 810 polluted_words = set(['unix', 'errno'])
6f88009e 811 if protect and (name in c89_words | c99_words | c11_words | gcc_words | cpp_words | polluted_words):
427a1a2c 812 return "q_" + name
18df515e 813 return name.translate(c_name_trans)
0f923be2 814
c6405b54
EB
815# Map type @name to the C typedef name for the list form.
816#
817# ['Name'] -> 'NameList', ['x-Foo'] -> 'x_FooList', ['int'] -> 'intList'
0f923be2 818def c_list_type(name):
c6405b54 819 return type_name(name) + 'List'
0f923be2 820
c6405b54
EB
821# Map type @value to the C typedef form.
822#
823# Used for converting 'type' from a 'member':'type' qapi definition
824# into the alphanumeric portion of the type for a generated C parameter,
825# as well as generated C function names. See c_type() for the rest of
826# the conversion such as adding '*' on pointer types.
827# 'int' -> 'int', '[x-Foo]' -> 'x_FooList', '__a.b_c' -> '__a_b_c'
d5573446
EB
828def type_name(value):
829 if type(value) == list:
830 return c_list_type(value[0])
c6405b54
EB
831 if value in builtin_types.keys():
832 return value
833 return c_name(value)
0f923be2 834
fd41dd4e 835def add_name(name, info, meta, implicit = False):
4dc2e690 836 global all_names
fd41dd4e 837 check_name(info, "'%s'" % meta, name)
4dc2e690
EB
838 if name in all_names:
839 raise QAPIExprError(info,
840 "%s '%s' is already defined"
841 % (all_names[name], name))
842 if not implicit and name[-4:] == 'Kind':
843 raise QAPIExprError(info,
844 "%s '%s' should not end in 'Kind'"
845 % (meta, name))
846 all_names[name] = meta
b35284ea 847
4dc2e690 848def add_struct(definition, info):
b35284ea 849 global struct_types
fd41dd4e
EB
850 name = definition['struct']
851 add_name(name, info, 'struct')
b35284ea
KW
852 struct_types.append(definition)
853
854def find_struct(name):
855 global struct_types
856 for struct in struct_types:
fd41dd4e 857 if struct['struct'] == name:
b35284ea
KW
858 return struct
859 return None
0f923be2 860
4dc2e690 861def add_union(definition, info):
ea66c6d8 862 global union_types
4dc2e690
EB
863 name = definition['union']
864 add_name(name, info, 'union')
ab916fad 865 union_types.append(definition)
ea66c6d8
KW
866
867def find_union(name):
868 global union_types
869 for union in union_types:
870 if union['union'] == name:
871 return union
872 return None
873
4dc2e690 874def add_enum(name, info, enum_values = None, implicit = False):
0f923be2 875 global enum_types
4dc2e690 876 add_name(name, info, 'enum', implicit)
dad1fcab 877 enum_types.append({"enum_name": name, "enum_values": enum_values})
0f923be2 878
dad1fcab 879def find_enum(name):
0f923be2 880 global enum_types
dad1fcab
WX
881 for enum in enum_types:
882 if enum['enum_name'] == name:
883 return enum
884 return None
885
886def is_enum(name):
887 return find_enum(name) != None
0f923be2 888
05dfb26c 889eatspace = '\033EATSPACE.'
d5573446 890pointer_suffix = ' *' + eatspace
05dfb26c 891
c6405b54
EB
892# Map type @name to its C type expression.
893# If @is_param, const-qualify the string type.
894#
895# This function is used for computing the full C type of 'member':'name'.
05dfb26c
AK
896# A special suffix is added in c_type() for pointer types, and it's
897# stripped in mcgen(). So please notice this when you check the return
898# value of c_type() outside mcgen().
d5573446
EB
899def c_type(value, is_param=False):
900 if value == 'str':
0d14eeb2 901 if is_param:
d5573446
EB
902 return 'const char' + pointer_suffix
903 return 'char' + pointer_suffix
05dfb26c 904
d5573446 905 elif value == 'int':
0f923be2 906 return 'int64_t'
d5573446
EB
907 elif (value == 'int8' or value == 'int16' or value == 'int32' or
908 value == 'int64' or value == 'uint8' or value == 'uint16' or
909 value == 'uint32' or value == 'uint64'):
910 return value + '_t'
911 elif value == 'size':
092705d4 912 return 'uint64_t'
d5573446 913 elif value == 'bool':
0f923be2 914 return 'bool'
d5573446 915 elif value == 'number':
0f923be2 916 return 'double'
d5573446
EB
917 elif type(value) == list:
918 return c_list_type(value[0]) + pointer_suffix
919 elif is_enum(value):
c6405b54 920 return c_name(value)
d5573446 921 elif value == None:
0f923be2 922 return 'void'
d5573446
EB
923 elif value in events:
924 return camel_case(value) + 'Event' + pointer_suffix
0f923be2 925 else:
d5573446
EB
926 # complex type name
927 assert isinstance(value, str) and value != ""
c6405b54 928 return c_name(value) + pointer_suffix
05dfb26c 929
d5573446
EB
930def is_c_ptr(value):
931 return c_type(value).endswith(pointer_suffix)
0f923be2
MR
932
933def genindent(count):
934 ret = ""
935 for i in range(count):
936 ret += " "
937 return ret
938
939indent_level = 0
940
941def push_indent(indent_amount=4):
942 global indent_level
943 indent_level += indent_amount
944
945def pop_indent(indent_amount=4):
946 global indent_level
947 indent_level -= indent_amount
948
949def cgen(code, **kwds):
950 indent = genindent(indent_level)
951 lines = code.split('\n')
952 lines = map(lambda x: indent + x, lines)
953 return '\n'.join(lines) % kwds + '\n'
954
955def mcgen(code, **kwds):
05dfb26c
AK
956 raw = cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
957 return re.sub(re.escape(eatspace) + ' *', '', raw)
0f923be2
MR
958
959def basename(filename):
960 return filename.split("/")[-1]
961
962def guardname(filename):
d8e1f214
MR
963 guard = basename(filename).rsplit(".", 1)[0]
964 for substr in [".", " ", "-"]:
965 guard = guard.replace(substr, "_")
966 return guard.upper() + '_H'
c0afa9c5
MR
967
968def guardstart(name):
969 return mcgen('''
970
971#ifndef %(name)s
972#define %(name)s
973
974''',
975 name=guardname(name))
976
977def guardend(name):
978 return mcgen('''
979
980#endif /* %(name)s */
981
982''',
983 name=guardname(name))
2114f5a9
MA
984
985def parse_command_line(extra_options = "", extra_long_options = []):
986
987 try:
988 opts, args = getopt.gnu_getopt(sys.argv[1:],
16d80f61 989 "chp:o:" + extra_options,
2114f5a9 990 ["source", "header", "prefix=",
16d80f61 991 "output-dir="] + extra_long_options)
2114f5a9 992 except getopt.GetoptError, err:
b4540968 993 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
2114f5a9
MA
994 sys.exit(1)
995
996 output_dir = ""
997 prefix = ""
998 do_c = False
999 do_h = False
1000 extra_opts = []
1001
1002 for oa in opts:
1003 o, a = oa
1004 if o in ("-p", "--prefix"):
1005 prefix = a
2114f5a9
MA
1006 elif o in ("-o", "--output-dir"):
1007 output_dir = a + "/"
1008 elif o in ("-c", "--source"):
1009 do_c = True
1010 elif o in ("-h", "--header"):
1011 do_h = True
1012 else:
1013 extra_opts.append(oa)
1014
1015 if not do_c and not do_h:
1016 do_c = True
1017 do_h = True
1018
16d80f61
MA
1019 if len(args) != 1:
1020 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
b4540968 1021 sys.exit(1)
54414047 1022 fname = args[0]
b4540968 1023
54414047 1024 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
12f8e1b9
MA
1025
1026def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1027 c_comment, h_comment):
1028 c_file = output_dir + prefix + c_file
1029 h_file = output_dir + prefix + h_file
1030
1031 try:
1032 os.makedirs(output_dir)
1033 except os.error, e:
1034 if e.errno != errno.EEXIST:
1035 raise
1036
1037 def maybe_open(really, name, opt):
1038 if really:
1039 return open(name, opt)
1040 else:
1041 import StringIO
1042 return StringIO.StringIO()
1043
1044 fdef = maybe_open(do_c, c_file, 'w')
1045 fdecl = maybe_open(do_h, h_file, 'w')
1046
1047 fdef.write(mcgen('''
1048/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1049%(comment)s
1050''',
1051 comment = c_comment))
1052
1053 fdecl.write(mcgen('''
1054/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1055%(comment)s
1056#ifndef %(guard)s
1057#define %(guard)s
1058
1059''',
1060 comment = h_comment, guard = guardname(h_file)))
1061
1062 return (fdef, fdecl)
1063
1064def close_output(fdef, fdecl):
1065 fdecl.write('''
1066#endif
1067''')
12f8e1b9 1068 fdecl.close()
12f8e1b9 1069 fdef.close()