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