blob: 6b2aa6e3dfe43c85fd13627eab8a16c35b7a02b3 [file] [log] [blame]
Michael Roth0f923be2011-07-19 14:50:39 -05001#
2# QAPI helper library
3#
4# Copyright IBM, Corp. 2011
Eric Blakee4083112016-01-29 06:48:41 -07005# Copyright (c) 2013-2016 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
Lluís Vilanovaa719a272014-05-07 20:46:15 +020014import re
Michael Roth0f923be2011-07-19 14:50:39 -050015from ordereddict import OrderedDict
Markus Armbruster12f8e1b2015-04-02 14:46:39 +020016import errno
Markus Armbruster2114f5a2015-04-02 13:12:21 +020017import getopt
Lluís Vilanova33aaad52014-05-02 15:52:35 +020018import os
Markus Armbruster2caba362013-07-27 17:41:56 +020019import sys
Markus Armbruster47299262015-05-14 06:50:47 -060020import string
Michael Roth0f923be2011-07-19 14:50:39 -050021
Eric Blakeb52c4b92015-05-04 09:05:00 -060022builtin_types = {
Kevin Wolf69dd62d2013-07-08 16:14:21 +020023 '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',
Eric Blakecb17f792015-05-04 09:05:01 -060035 'size': 'QTYPE_QINT',
Eric Blake1310a3d2015-12-01 22:20:46 -070036 'any': None, # any QType possible, actually
Eric Blake7264f5c2015-12-01 22:20:47 -070037 'QType': 'QTYPE_QSTRING',
Kevin Wolf69dd62d2013-07-08 16:14:21 +020038}
39
Eric Blake10d4d992015-05-04 09:05:23 -060040# Whitelist of commands allowed to return a non-dictionary
41returns_whitelist = [
42 # From QMP:
43 'human-monitor-command',
Markus Armbruster6eb39372015-09-16 13:06:25 +020044 'qom-get',
Eric Blake10d4d992015-05-04 09:05:23 -060045 'query-migrate-cache-size',
46 'query-tpm-models',
47 'query-tpm-types',
48 'ringbuf-read',
49
50 # From QGA:
51 'guest-file-open',
52 'guest-fsfreeze-freeze',
53 'guest-fsfreeze-freeze-list',
54 'guest-fsfreeze-status',
55 'guest-fsfreeze-thaw',
56 'guest-get-time',
57 'guest-set-vcpus',
58 'guest-sync',
59 'guest-sync-delimited',
Eric Blake10d4d992015-05-04 09:05:23 -060060]
61
Eric Blake893e1f22015-12-01 22:20:57 -070062# Whitelist of entities allowed to violate case conventions
63case_whitelist = [
64 # From QMP:
65 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
66 'CpuInfoBase', # CPU, visible through query-cpu
67 'CpuInfoMIPS', # PC, visible through query-cpu
68 'CpuInfoTricore', # PC, visible through query-cpu
Eric Blake893e1f22015-12-01 22:20:57 -070069 'QapiErrorClass', # all members, visible through errors
70 'UuidInfo', # UUID, visible through query-uuid
71 'X86CPURegister32', # all members, visible indirectly through qom-get
72]
73
Eric Blake4dc2e692015-05-04 09:05:17 -060074enum_types = []
75struct_types = []
76union_types = []
77events = []
78all_names = {}
79
Markus Armbruster00e4b282015-06-10 10:04:36 +020080#
81# Parsing the schema into expressions
82#
83
Eric Blake437db252015-09-29 16:21:02 -060084
Lluís Vilanovaa719a272014-05-07 20:46:15 +020085def error_path(parent):
86 res = ""
87 while parent:
88 res = ("In file included from %s:%d:\n" % (parent['file'],
89 parent['line'])) + res
90 parent = parent['parent']
91 return res
92
Eric Blake437db252015-09-29 16:21:02 -060093
Markus Armbruster2caba362013-07-27 17:41:56 +020094class QAPISchemaError(Exception):
95 def __init__(self, schema, msg):
Eric Blake59b00542015-09-29 16:21:01 -060096 Exception.__init__(self)
Markus Armbruster54414042015-06-09 16:22:45 +020097 self.fname = schema.fname
Markus Armbruster2caba362013-07-27 17:41:56 +020098 self.msg = msg
Wenchao Xia515b9432014-03-04 18:44:33 -080099 self.col = 1
100 self.line = schema.line
101 for ch in schema.src[schema.line_pos:schema.pos]:
102 if ch == '\t':
Markus Armbruster2caba362013-07-27 17:41:56 +0200103 self.col = (self.col + 7) % 8 + 1
104 else:
105 self.col += 1
Markus Armbruster54414042015-06-09 16:22:45 +0200106 self.info = schema.incl_info
Markus Armbruster2caba362013-07-27 17:41:56 +0200107
108 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200109 return error_path(self.info) + \
Markus Armbruster54414042015-06-09 16:22:45 +0200110 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
Markus Armbruster2caba362013-07-27 17:41:56 +0200111
Eric Blake437db252015-09-29 16:21:02 -0600112
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800113class QAPIExprError(Exception):
114 def __init__(self, expr_info, msg):
Eric Blake59b00542015-09-29 16:21:01 -0600115 Exception.__init__(self)
Eric Blake7618b912015-10-12 22:22:22 -0600116 assert expr_info
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200117 self.info = expr_info
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800118 self.msg = msg
119
120 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200121 return error_path(self.info['parent']) + \
122 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800123
Eric Blake437db252015-09-29 16:21:02 -0600124
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200125class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500126
Eric Blake437db252015-09-29 16:21:02 -0600127 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200128 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200129 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200130 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200131 previously_included.append(abs_fname)
132 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200133 self.src = fp.read()
134 if self.src == '' or self.src[-1] != '\n':
135 self.src += '\n'
136 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800137 self.line = 1
138 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200139 self.exprs = []
140 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500141
Eric Blake437db252015-09-29 16:21:02 -0600142 while self.tok is not None:
Markus Armbruster54414042015-06-09 16:22:45 +0200143 expr_info = {'file': fname, 'line': self.line,
144 'parent': self.incl_info}
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200145 expr = self.get_expr(False)
146 if isinstance(expr, dict) and "include" in expr:
147 if len(expr) != 1:
Eric Blake437db252015-09-29 16:21:02 -0600148 raise QAPIExprError(expr_info,
149 "Invalid 'include' directive")
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200150 include = expr["include"]
151 if not isinstance(include, str):
152 raise QAPIExprError(expr_info,
Eric Blake7408fb62015-09-29 16:21:00 -0600153 "Value of 'include' must be a string")
Markus Armbruster54414042015-06-09 16:22:45 +0200154 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
155 include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200156 # catch inclusion cycle
157 inf = expr_info
158 while inf:
159 if incl_abs_fname == os.path.abspath(inf['file']):
Stefan Hajnoczi7ac9a9d2014-08-27 12:08:51 +0100160 raise QAPIExprError(expr_info, "Inclusion loop for %s"
161 % include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200162 inf = inf['parent']
Benoît Canet24fd8482014-05-16 12:51:56 +0200163 # skip multiple include of the same file
Markus Armbruster54414042015-06-09 16:22:45 +0200164 if incl_abs_fname in previously_included:
Benoît Canet24fd8482014-05-16 12:51:56 +0200165 continue
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200166 try:
Markus Armbruster54414042015-06-09 16:22:45 +0200167 fobj = open(incl_abs_fname, 'r')
Markus Armbruster291928a2015-12-18 08:52:41 +0100168 except IOError as e:
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200169 raise QAPIExprError(expr_info,
170 '%s: %s' % (e.strerror, include))
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200171 exprs_include = QAPISchemaParser(fobj, previously_included,
172 expr_info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200173 self.exprs.extend(exprs_include.exprs)
174 else:
175 expr_elem = {'expr': expr,
176 'info': expr_info}
177 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500178
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200179 def accept(self):
180 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200181 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200182 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200183 self.cursor += 1
184 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500185
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200186 if self.tok == '#':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200187 self.cursor = self.src.find('\n', self.cursor)
Eric Blake8712fa52015-10-26 16:34:41 -0600188 elif self.tok in "{}:,[]":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200189 return
190 elif self.tok == "'":
191 string = ''
192 esc = False
193 while True:
194 ch = self.src[self.cursor]
195 self.cursor += 1
196 if ch == '\n':
Markus Armbruster2caba362013-07-27 17:41:56 +0200197 raise QAPISchemaError(self,
198 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200199 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600200 if ch == 'b':
201 string += '\b'
202 elif ch == 'f':
203 string += '\f'
204 elif ch == 'n':
205 string += '\n'
206 elif ch == 'r':
207 string += '\r'
208 elif ch == 't':
209 string += '\t'
210 elif ch == 'u':
211 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600212 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600213 ch = self.src[self.cursor]
214 self.cursor += 1
215 if ch not in "0123456789abcdefABCDEF":
216 raise QAPISchemaError(self,
217 '\\u escape needs 4 '
218 'hex digits')
219 value = (value << 4) + int(ch, 16)
220 # If Python 2 and 3 didn't disagree so much on
221 # how to handle Unicode, then we could allow
222 # Unicode string defaults. But most of QAPI is
223 # ASCII-only, so we aren't losing much for now.
224 if not value or value > 0x7f:
225 raise QAPISchemaError(self,
226 'For now, \\u escape '
227 'only supports non-zero '
228 'values up to \\u007f')
229 string += chr(value)
230 elif ch in "\\/'\"":
231 string += ch
232 else:
233 raise QAPISchemaError(self,
Eric Blake437db252015-09-29 16:21:02 -0600234 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200235 esc = False
236 elif ch == "\\":
237 esc = True
238 elif ch == "'":
239 self.val = string
240 return
241 else:
242 string += ch
Markus Armbrustere565d932015-06-10 08:24:58 +0200243 elif self.src.startswith("true", self.pos):
244 self.val = True
245 self.cursor += 3
246 return
247 elif self.src.startswith("false", self.pos):
248 self.val = False
249 self.cursor += 4
250 return
251 elif self.src.startswith("null", self.pos):
252 self.val = None
253 self.cursor += 3
254 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200255 elif self.tok == '\n':
256 if self.cursor == len(self.src):
257 self.tok = None
258 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800259 self.line += 1
260 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200261 elif not self.tok.isspace():
262 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500263
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200264 def get_members(self):
265 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200266 if self.tok == '}':
267 self.accept()
268 return expr
269 if self.tok != "'":
270 raise QAPISchemaError(self, 'Expected string or "}"')
271 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200272 key = self.val
273 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200274 if self.tok != ':':
275 raise QAPISchemaError(self, 'Expected ":"')
276 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800277 if key in expr:
278 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200279 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200280 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200281 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200282 return expr
283 if self.tok != ',':
284 raise QAPISchemaError(self, 'Expected "," or "}"')
285 self.accept()
286 if self.tok != "'":
287 raise QAPISchemaError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500288
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200289 def get_values(self):
290 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200291 if self.tok == ']':
292 self.accept()
293 return expr
Eric Blake437db252015-09-29 16:21:02 -0600294 if self.tok not in "{['tfn":
Fam Zhenge53188a2015-05-04 09:05:18 -0600295 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
296 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200297 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200298 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200299 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200300 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200301 return expr
302 if self.tok != ',':
303 raise QAPISchemaError(self, 'Expected "," or "]"')
304 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500305
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200306 def get_expr(self, nested):
307 if self.tok != '{' and not nested:
308 raise QAPISchemaError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200309 if self.tok == '{':
310 self.accept()
311 expr = self.get_members()
312 elif self.tok == '[':
313 self.accept()
314 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600315 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200316 expr = self.val
317 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200318 else:
319 raise QAPISchemaError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200320 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200321
Markus Armbruster00e4b282015-06-10 10:04:36 +0200322#
323# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200324# TODO fold into QAPISchema
325# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200326#
327
Eric Blake437db252015-09-29 16:21:02 -0600328
Eric Blake14f00c62016-03-03 09:16:43 -0700329def find_base_members(base):
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800330 base_struct_define = find_struct(base)
331 if not base_struct_define:
332 return None
333 return base_struct_define['data']
334
Eric Blake437db252015-09-29 16:21:02 -0600335
Eric Blake811d04f2015-05-04 09:05:10 -0600336# Return the qtype of an alternate branch, or None on error.
337def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600338 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600339 return builtin_types[qapi_type]
340 elif find_struct(qapi_type):
341 return "QTYPE_QDICT"
342 elif find_enum(qapi_type):
343 return "QTYPE_QSTRING"
Eric Blake811d04f2015-05-04 09:05:10 -0600344 elif find_union(qapi_type):
345 return "QTYPE_QDICT"
Eric Blake44bd1272015-05-04 09:05:08 -0600346 return None
347
Eric Blake437db252015-09-29 16:21:02 -0600348
Wenchao Xiabceae762014-03-06 17:08:56 -0800349# Return the discriminator enum define if discriminator is specified as an
350# enum type, otherwise return None.
351def discriminator_find_enum_define(expr):
352 base = expr.get('base')
353 discriminator = expr.get('discriminator')
354
355 if not (discriminator and base):
356 return None
357
Eric Blake14f00c62016-03-03 09:16:43 -0700358 base_members = find_base_members(base)
359 if not base_members:
Wenchao Xiabceae762014-03-06 17:08:56 -0800360 return None
361
Eric Blake14f00c62016-03-03 09:16:43 -0700362 discriminator_type = base_members.get(discriminator)
Wenchao Xiabceae762014-03-06 17:08:56 -0800363 if not discriminator_type:
364 return None
365
366 return find_enum(discriminator_type)
367
Eric Blake437db252015-09-29 16:21:02 -0600368
Eric Blake59a92fe2015-11-18 01:52:56 -0700369# Names must be letters, numbers, -, and _. They must start with letter,
370# except for downstream extensions which must start with __RFQDN_.
371# Dots are only valid in the downstream extension prefix.
372valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
373 '[a-zA-Z][a-zA-Z0-9_-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600374
375
376def check_name(expr_info, source, name, allow_optional=False,
377 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600378 global valid_name
379 membername = name
380
381 if not isinstance(name, str):
382 raise QAPIExprError(expr_info,
383 "%s requires a string name" % source)
384 if name.startswith('*'):
385 membername = name[1:]
386 if not allow_optional:
387 raise QAPIExprError(expr_info,
388 "%s does not allow optional name '%s'"
389 % (source, name))
390 # Enum members can start with a digit, because the generated C
391 # code always prefixes it with the enum name
Eric Blake59a92fe2015-11-18 01:52:56 -0700392 if enum_member and membername[0].isdigit():
393 membername = 'D' + membername
Eric Blake9fb081e2015-10-26 16:34:44 -0600394 # Reserve the entire 'q_' namespace for c_name()
395 if not valid_name.match(membername) or \
396 c_name(membername, False).startswith('q_'):
Eric Blakec9e0a792015-05-04 09:05:22 -0600397 raise QAPIExprError(expr_info,
398 "%s uses invalid name '%s'" % (source, name))
399
Eric Blake437db252015-09-29 16:21:02 -0600400
401def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200402 global all_names
403 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200404 # FIXME should reject names that differ only in '_' vs. '.'
405 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200406 if name in all_names:
407 raise QAPIExprError(info,
408 "%s '%s' is already defined"
409 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600410 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200411 raise QAPIExprError(info,
Eric Blake255960d2015-10-26 16:34:43 -0600412 "%s '%s' should not end in '%s'"
413 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200414 all_names[name] = meta
415
Eric Blake437db252015-09-29 16:21:02 -0600416
Markus Armbruster00e4b282015-06-10 10:04:36 +0200417def add_struct(definition, info):
418 global struct_types
419 name = definition['struct']
420 add_name(name, info, 'struct')
421 struct_types.append(definition)
422
Eric Blake437db252015-09-29 16:21:02 -0600423
Markus Armbruster00e4b282015-06-10 10:04:36 +0200424def find_struct(name):
425 global struct_types
426 for struct in struct_types:
427 if struct['struct'] == name:
428 return struct
429 return None
430
Eric Blake437db252015-09-29 16:21:02 -0600431
Markus Armbruster00e4b282015-06-10 10:04:36 +0200432def add_union(definition, info):
433 global union_types
434 name = definition['union']
435 add_name(name, info, 'union')
436 union_types.append(definition)
437
Eric Blake437db252015-09-29 16:21:02 -0600438
Markus Armbruster00e4b282015-06-10 10:04:36 +0200439def find_union(name):
440 global union_types
441 for union in union_types:
442 if union['union'] == name:
443 return union
444 return None
445
Eric Blake437db252015-09-29 16:21:02 -0600446
447def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200448 global enum_types
449 add_name(name, info, 'enum', implicit)
450 enum_types.append({"enum_name": name, "enum_values": enum_values})
451
Eric Blake437db252015-09-29 16:21:02 -0600452
Markus Armbruster00e4b282015-06-10 10:04:36 +0200453def find_enum(name):
454 global enum_types
455 for enum in enum_types:
456 if enum['enum_name'] == name:
457 return enum
458 return None
459
Markus Armbruster00e4b282015-06-10 10:04:36 +0200460
Eric Blake437db252015-09-29 16:21:02 -0600461def is_enum(name):
462 return find_enum(name) is not None
463
464
465def check_type(expr_info, source, value, allow_array=False,
466 allow_dict=False, allow_optional=False,
467 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600468 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600469
470 if value is None:
471 return
472
Eric Blakedd883c62015-05-04 09:05:21 -0600473 # Check if array type for value is okay
474 if isinstance(value, list):
475 if not allow_array:
476 raise QAPIExprError(expr_info,
477 "%s cannot be an array" % source)
478 if len(value) != 1 or not isinstance(value[0], str):
479 raise QAPIExprError(expr_info,
480 "%s: array type must contain single type name"
481 % source)
482 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600483
484 # Check if type name for value is okay
485 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600486 if value not in all_names:
Eric Blakedd883c62015-05-04 09:05:21 -0600487 raise QAPIExprError(expr_info,
488 "%s uses unknown type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200489 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600490 if not all_names[value] in allow_metas:
491 raise QAPIExprError(expr_info,
492 "%s cannot use %s type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200493 % (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600494 return
495
Eric Blakedd883c62015-05-04 09:05:21 -0600496 if not allow_dict:
497 raise QAPIExprError(expr_info,
498 "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200499
500 if not isinstance(value, OrderedDict):
501 raise QAPIExprError(expr_info,
502 "%s should be a dictionary or type name" % source)
503
504 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600505 for (key, arg) in value.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600506 check_name(expr_info, "Member of %s" % source, key,
507 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600508 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Eric Blake9fb081e2015-10-26 16:34:44 -0600509 raise QAPIExprError(expr_info,
510 "Member of %s uses reserved name '%s'"
511 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600512 # Todo: allow dictionaries to represent default values of
513 # an optional argument.
Eric Blakedd883c62015-05-04 09:05:21 -0600514 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200515 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600516 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600517 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600518
Eric Blake437db252015-09-29 16:21:02 -0600519
Eric Blakedd883c62015-05-04 09:05:21 -0600520def check_command(expr, expr_info):
521 name = expr['command']
Eric Blake2cbf0992015-05-04 09:05:24 -0600522
Eric Blakedd883c62015-05-04 09:05:21 -0600523 check_type(expr_info, "'data' for command '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600524 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200525 allow_metas=['struct'])
Eric Blake10d4d992015-05-04 09:05:23 -0600526 returns_meta = ['union', 'struct']
527 if name in returns_whitelist:
528 returns_meta += ['built-in', 'alternate', 'enum']
Eric Blakedd883c62015-05-04 09:05:21 -0600529 check_type(expr_info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200530 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200531 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600532
Eric Blake437db252015-09-29 16:21:02 -0600533
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200534def check_event(expr, expr_info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600535 global events
536 name = expr['event']
Eric Blake4dc2e692015-05-04 09:05:17 -0600537
Eric Blake4dc2e692015-05-04 09:05:17 -0600538 events.append(name)
Eric Blakedd883c62015-05-04 09:05:21 -0600539 check_type(expr_info, "'data' for event '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600540 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster315932b2015-07-01 10:12:24 +0200541 allow_metas=['struct'])
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200542
Eric Blake437db252015-09-29 16:21:02 -0600543
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800544def check_union(expr, expr_info):
545 name = expr['union']
546 base = expr.get('base')
547 discriminator = expr.get('discriminator')
548 members = expr['data']
549
Eric Blake811d04f2015-05-04 09:05:10 -0600550 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600551
552 # With no discriminator it is a simple union.
553 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600554 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600555 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600556 if base is not None:
557 raise QAPIExprError(expr_info,
Eric Blake811d04f2015-05-04 09:05:10 -0600558 "Simple union '%s' must not have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600559 % name)
560
561 # Else, it's a flat union.
562 else:
563 # The object must have a string member 'base'.
Eric Blake376863e2015-09-29 16:21:07 -0600564 check_type(expr_info, "'base' for union '%s'" % name,
565 base, allow_metas=['struct'])
566 if not base:
Eric Blake44bd1272015-05-04 09:05:08 -0600567 raise QAPIExprError(expr_info,
Eric Blake376863e2015-09-29 16:21:07 -0600568 "Flat union '%s' must have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600569 % name)
Eric Blake14f00c62016-03-03 09:16:43 -0700570 base_members = find_base_members(base)
571 assert base_members
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800572
Eric Blakec9e0a792015-05-04 09:05:22 -0600573 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600574 # member of the base struct.
Eric Blakec9e0a792015-05-04 09:05:22 -0600575 check_name(expr_info, "Discriminator of flat union '%s'" % name,
576 discriminator)
Eric Blake14f00c62016-03-03 09:16:43 -0700577 discriminator_type = base_members.get(discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800578 if not discriminator_type:
579 raise QAPIExprError(expr_info,
580 "Discriminator '%s' is not a member of base "
Eric Blakefd41dd42015-05-04 09:05:25 -0600581 "struct '%s'"
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800582 % (discriminator, base))
583 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600584 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800585 # Do not allow string discriminator
586 if not enum_define:
587 raise QAPIExprError(expr_info,
588 "Discriminator '%s' must be of enumeration "
589 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800590
Eric Blake02a57ae2016-02-17 23:48:16 -0700591 # Check every branch; don't allow an empty union
592 if len(members) == 0:
593 raise QAPIExprError(expr_info,
594 "Union '%s' cannot have empty 'data'" % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800595 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600596 check_name(expr_info, "Member of union '%s'" % name, key)
597
Eric Blake01cfbaa2015-12-01 22:20:58 -0700598 # Each value must name a known type
Eric Blakedd883c62015-05-04 09:05:21 -0600599 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200600 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakedd883c62015-05-04 09:05:21 -0600601
Eric Blake44bd1272015-05-04 09:05:08 -0600602 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700603 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600604 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600605 if key not in enum_define['enum_values']:
Eric Blake44bd1272015-05-04 09:05:08 -0600606 raise QAPIExprError(expr_info,
607 "Discriminator value '%s' is not found in "
608 "enum '%s'" %
609 (key, enum_define["enum_name"]))
610
Eric Blake437db252015-09-29 16:21:02 -0600611
Eric Blake811d04f2015-05-04 09:05:10 -0600612def check_alternate(expr, expr_info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600613 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600614 members = expr['data']
Eric Blake811d04f2015-05-04 09:05:10 -0600615 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600616
Eric Blake02a57ae2016-02-17 23:48:16 -0700617 # Check every branch; require at least two branches
618 if len(members) < 2:
619 raise QAPIExprError(expr_info,
620 "Alternate '%s' should have at least two branches "
621 "in 'data'" % name)
Eric Blake811d04f2015-05-04 09:05:10 -0600622 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600623 check_name(expr_info, "Member of alternate '%s'" % name, key)
624
Eric Blake811d04f2015-05-04 09:05:10 -0600625 # Ensure alternates have no type conflicts.
Eric Blakedd883c62015-05-04 09:05:21 -0600626 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
627 value,
628 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600629 qtype = find_alternate_member_qtype(value)
Eric Blake46534302016-02-17 23:48:17 -0700630 if not qtype:
631 raise QAPIExprError(expr_info,
632 "Alternate '%s' member '%s' cannot use "
633 "type '%s'" % (name, key, value))
Eric Blake811d04f2015-05-04 09:05:10 -0600634 if qtype in types_seen:
635 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600636 "Alternate '%s' member '%s' can't "
Eric Blake811d04f2015-05-04 09:05:10 -0600637 "be distinguished from member '%s'"
638 % (name, key, types_seen[qtype]))
639 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800640
Eric Blake437db252015-09-29 16:21:02 -0600641
Eric Blakecf393592015-05-04 09:05:04 -0600642def check_enum(expr, expr_info):
643 name = expr['enum']
644 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100645 prefix = expr.get('prefix')
Eric Blakecf393592015-05-04 09:05:04 -0600646
647 if not isinstance(members, list):
648 raise QAPIExprError(expr_info,
649 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100650 if prefix is not None and not isinstance(prefix, str):
651 raise QAPIExprError(expr_info,
652 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600653 for member in members:
Eric Blake437db252015-09-29 16:21:02 -0600654 check_name(expr_info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600655 enum_member=True)
Eric Blakecf393592015-05-04 09:05:04 -0600656
Eric Blake437db252015-09-29 16:21:02 -0600657
Eric Blakedd883c62015-05-04 09:05:21 -0600658def check_struct(expr, expr_info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600659 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600660 members = expr['data']
661
Eric Blakefd41dd42015-05-04 09:05:25 -0600662 check_type(expr_info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600663 allow_dict=True, allow_optional=True)
Eric Blakefd41dd42015-05-04 09:05:25 -0600664 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600665 allow_metas=['struct'])
666
Eric Blake437db252015-09-29 16:21:02 -0600667
Eric Blake0545f6b2015-05-04 09:05:15 -0600668def check_keys(expr_elem, meta, required, optional=[]):
669 expr = expr_elem['expr']
670 info = expr_elem['info']
671 name = expr[meta]
672 if not isinstance(name, str):
673 raise QAPIExprError(info,
674 "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600675 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600676 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600677 if key not in required and key not in optional:
Eric Blake0545f6b2015-05-04 09:05:15 -0600678 raise QAPIExprError(info,
679 "Unknown key '%s' in %s '%s'"
680 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600681 if (key == 'gen' or key == 'success-response') and value is not False:
Eric Blake2cbf0992015-05-04 09:05:24 -0600682 raise QAPIExprError(info,
683 "'%s' of %s '%s' should only use false value"
684 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600685 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600686 if key not in expr:
Eric Blake0545f6b2015-05-04 09:05:15 -0600687 raise QAPIExprError(info,
688 "Key '%s' is missing from %s '%s'"
689 % (key, meta, name))
690
Eric Blake437db252015-09-29 16:21:02 -0600691
Markus Armbruster4d076d62015-06-10 08:55:21 +0200692def check_exprs(exprs):
693 global all_names
694
695 # Learn the types and check for valid expression keys
696 for builtin in builtin_types.keys():
697 all_names[builtin] = 'built-in'
698 for expr_elem in exprs:
699 expr = expr_elem['expr']
700 info = expr_elem['info']
Eric Blake437db252015-09-29 16:21:02 -0600701 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100702 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200703 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600704 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200705 check_keys(expr_elem, 'union', ['data'],
706 ['base', 'discriminator'])
707 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600708 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200709 check_keys(expr_elem, 'alternate', ['data'])
710 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600711 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200712 check_keys(expr_elem, 'struct', ['data'], ['base'])
713 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600714 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200715 check_keys(expr_elem, 'command', [],
716 ['data', 'returns', 'gen', 'success-response'])
717 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600718 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200719 check_keys(expr_elem, 'event', [], ['data'])
720 add_name(expr['event'], info, 'event')
721 else:
722 raise QAPIExprError(expr_elem['info'],
723 "Expression is missing metatype")
724
725 # Try again for hidden UnionKind enum
726 for expr_elem in exprs:
727 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600728 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200729 if not discriminator_find_enum_define(expr):
730 add_enum('%sKind' % expr['union'], expr_elem['info'],
731 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600732 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200733 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
734 implicit=True)
735
736 # Validate that exprs make sense
737 for expr_elem in exprs:
738 expr = expr_elem['expr']
739 info = expr_elem['info']
740
Eric Blake437db252015-09-29 16:21:02 -0600741 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200742 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600743 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200744 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600745 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200746 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600747 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200748 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600749 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200750 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600751 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200752 check_event(expr, info)
753 else:
754 assert False, 'unexpected meta type'
755
Markus Armbrusterac882192015-09-16 13:06:05 +0200756 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600757
Markus Armbrusterac882192015-09-16 13:06:05 +0200758
759#
760# Schema compiler frontend
761#
762
763class QAPISchemaEntity(object):
764 def __init__(self, name, info):
765 assert isinstance(name, str)
766 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -0600767 # For explicitly defined entities, info points to the (explicit)
768 # definition. For builtins (and their arrays), info is None.
769 # For implicitly defined entities, info points to a place that
770 # triggered the implicit definition (there may be more than one
771 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +0200772 self.info = info
773
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200774 def c_name(self):
775 return c_name(self.name)
776
Markus Armbrusterac882192015-09-16 13:06:05 +0200777 def check(self, schema):
778 pass
779
Eric Blake49823c42015-10-12 22:22:27 -0600780 def is_implicit(self):
781 return not self.info
782
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200783 def visit(self, visitor):
784 pass
785
786
787class QAPISchemaVisitor(object):
788 def visit_begin(self, schema):
789 pass
790
791 def visit_end(self):
792 pass
793
Eric Blake25a0d9c2015-10-12 22:22:21 -0600794 def visit_needed(self, entity):
795 # Default to visiting everything
796 return True
797
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200798 def visit_builtin_type(self, name, info, json_type):
799 pass
800
801 def visit_enum_type(self, name, info, values, prefix):
802 pass
803
804 def visit_array_type(self, name, info, element_type):
805 pass
806
807 def visit_object_type(self, name, info, base, members, variants):
808 pass
809
Markus Armbruster39a18152015-09-16 13:06:28 +0200810 def visit_object_type_flat(self, name, info, members, variants):
811 pass
812
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200813 def visit_alternate_type(self, name, info, variants):
814 pass
815
816 def visit_command(self, name, info, arg_type, ret_type,
817 gen, success_response):
818 pass
819
820 def visit_event(self, name, info, arg_type):
821 pass
822
Markus Armbrusterac882192015-09-16 13:06:05 +0200823
824class QAPISchemaType(QAPISchemaEntity):
Eric Blakebecceed2016-02-17 23:48:26 -0700825 def c_type(self, is_param=False, is_unboxed=False):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200826 return c_name(self.name) + pointer_suffix
827
828 def c_null(self):
829 return 'NULL'
830
831 def json_type(self):
832 pass
833
834 def alternate_qtype(self):
835 json2qtype = {
836 'string': 'QTYPE_QSTRING',
837 'number': 'QTYPE_QFLOAT',
838 'int': 'QTYPE_QINT',
839 'boolean': 'QTYPE_QBOOL',
840 'object': 'QTYPE_QDICT'
841 }
842 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +0200843
844
845class QAPISchemaBuiltinType(QAPISchemaType):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200846 def __init__(self, name, json_type, c_type, c_null):
Markus Armbrusterac882192015-09-16 13:06:05 +0200847 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200848 assert not c_type or isinstance(c_type, str)
849 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
850 'value')
851 self._json_type_name = json_type
852 self._c_type_name = c_type
853 self._c_null_val = c_null
854
855 def c_name(self):
856 return self.name
857
Eric Blakebecceed2016-02-17 23:48:26 -0700858 def c_type(self, is_param=False, is_unboxed=False):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200859 if is_param and self.name == 'str':
860 return 'const ' + self._c_type_name
861 return self._c_type_name
862
863 def c_null(self):
864 return self._c_null_val
865
866 def json_type(self):
867 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +0200868
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200869 def visit(self, visitor):
870 visitor.visit_builtin_type(self.name, self.info, self.json_type())
871
Markus Armbrusterac882192015-09-16 13:06:05 +0200872
873class QAPISchemaEnumType(QAPISchemaType):
874 def __init__(self, name, info, values, prefix):
875 QAPISchemaType.__init__(self, name, info)
876 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -0700877 assert isinstance(v, QAPISchemaMember)
878 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200879 assert prefix is None or isinstance(prefix, str)
880 self.values = values
881 self.prefix = prefix
882
883 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -0700884 seen = {}
885 for v in self.values:
886 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200887
Eric Blake99df5282015-10-12 22:22:32 -0600888 def is_implicit(self):
889 # See QAPISchema._make_implicit_enum_type()
Eric Blake8712fa52015-10-26 16:34:41 -0600890 return self.name.endswith('Kind')
Eric Blake99df5282015-10-12 22:22:32 -0600891
Eric Blakebecceed2016-02-17 23:48:26 -0700892 def c_type(self, is_param=False, is_unboxed=False):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200893 return c_name(self.name)
894
Eric Blake93bda4d2015-12-01 22:20:55 -0700895 def member_names(self):
896 return [v.name for v in self.values]
897
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200898 def c_null(self):
Eric Blake93bda4d2015-12-01 22:20:55 -0700899 return c_enum_const(self.name, (self.member_names() + ['_MAX'])[0],
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200900 self.prefix)
901
902 def json_type(self):
903 return 'string'
904
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200905 def visit(self, visitor):
906 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -0700907 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200908
Markus Armbrusterac882192015-09-16 13:06:05 +0200909
910class QAPISchemaArrayType(QAPISchemaType):
911 def __init__(self, name, info, element_type):
912 QAPISchemaType.__init__(self, name, info)
913 assert isinstance(element_type, str)
914 self._element_type_name = element_type
915 self.element_type = None
916
917 def check(self, schema):
918 self.element_type = schema.lookup_type(self._element_type_name)
919 assert self.element_type
920
Eric Blake99df5282015-10-12 22:22:32 -0600921 def is_implicit(self):
922 return True
923
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200924 def json_type(self):
925 return 'array'
926
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200927 def visit(self, visitor):
928 visitor.visit_array_type(self.name, self.info, self.element_type)
929
Markus Armbrusterac882192015-09-16 13:06:05 +0200930
931class QAPISchemaObjectType(QAPISchemaType):
932 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -0700933 # struct has local_members, optional base, and no variants
934 # flat union has base, variants, and no local_members
935 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +0200936 QAPISchemaType.__init__(self, name, info)
937 assert base is None or isinstance(base, str)
938 for m in local_members:
939 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -0700940 m.set_owner(name)
941 if variants is not None:
942 assert isinstance(variants, QAPISchemaObjectTypeVariants)
943 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200944 self._base_name = base
945 self.base = None
946 self.local_members = local_members
947 self.variants = variants
948 self.members = None
949
950 def check(self, schema):
Eric Blakebac54292015-12-01 22:20:59 -0700951 if self.members is False: # check for cycles
952 raise QAPIExprError(self.info,
953 "Object %s contains itself" % self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200954 if self.members:
955 return
956 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -0700957 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +0200958 if self._base_name:
959 self.base = schema.lookup_type(self._base_name)
960 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +0200961 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700962 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200963 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -0700964 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700965 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700966 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +0200967 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -0700968 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700969 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -0700970 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200971
Eric Blake14f00c62016-03-03 09:16:43 -0700972 # Check that the members of this type do not cause duplicate JSON members,
Eric Blake27b60ab2015-11-18 01:52:51 -0700973 # and update seen to track the members seen so far. Report any errors
974 # on behalf of info, which is not necessarily self.info
975 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -0700976 assert not self.variants # not implemented
977 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -0700978 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -0700979
Eric Blake99df5282015-10-12 22:22:32 -0600980 def is_implicit(self):
981 # See QAPISchema._make_implicit_object_type()
982 return self.name[0] == ':'
983
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200984 def c_name(self):
Eric Blake49823c42015-10-12 22:22:27 -0600985 assert not self.is_implicit()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200986 return QAPISchemaType.c_name(self)
987
Eric Blakebecceed2016-02-17 23:48:26 -0700988 def c_type(self, is_param=False, is_unboxed=False):
Eric Blake49823c42015-10-12 22:22:27 -0600989 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -0700990 if is_unboxed:
991 return c_name(self.name)
992 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200993
994 def json_type(self):
995 return 'object'
996
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200997 def visit(self, visitor):
998 visitor.visit_object_type(self.name, self.info,
999 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001000 visitor.visit_object_type_flat(self.name, self.info,
1001 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001002
Markus Armbrusterac882192015-09-16 13:06:05 +02001003
Eric Blaked44f9ac2015-12-01 22:20:54 -07001004class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001005 role = 'member'
1006
Eric Blaked44f9ac2015-12-01 22:20:54 -07001007 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001008 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001009 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001010 self.owner = None
1011
1012 def set_owner(self, name):
1013 assert not self.owner
1014 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001015
Eric Blake27b60ab2015-11-18 01:52:51 -07001016 def check_clash(self, info, seen):
1017 cname = c_name(self.name)
Eric Blake893e1f22015-12-01 22:20:57 -07001018 if cname.lower() != cname and self.owner not in case_whitelist:
1019 raise QAPIExprError(info,
1020 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001021 if cname in seen:
1022 raise QAPIExprError(info,
1023 "%s collides with %s"
1024 % (self.describe(), seen[cname].describe()))
1025 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001026
Eric Blake88d4ef82015-11-18 01:52:50 -07001027 def _pretty_owner(self):
1028 owner = self.owner
1029 if owner.startswith(':obj-'):
1030 # See QAPISchema._make_implicit_object_type() - reverse the
1031 # mapping there to create a nice human-readable description
1032 owner = owner[5:]
1033 if owner.endswith('-arg'):
1034 return '(parameter of %s)' % owner[:-4]
1035 else:
1036 assert owner.endswith('-wrapper')
1037 # Unreachable and not implemented
1038 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001039 if owner.endswith('Kind'):
1040 # See QAPISchema._make_implicit_enum_type()
1041 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001042 return '(%s of %s)' % (self.role, owner)
1043
1044 def describe(self):
1045 return "'%s' %s" % (self.name, self._pretty_owner())
1046
Markus Armbrusterac882192015-09-16 13:06:05 +02001047
Eric Blaked44f9ac2015-12-01 22:20:54 -07001048class QAPISchemaObjectTypeMember(QAPISchemaMember):
1049 def __init__(self, name, typ, optional):
1050 QAPISchemaMember.__init__(self, name)
1051 assert isinstance(typ, str)
1052 assert isinstance(optional, bool)
1053 self._type_name = typ
1054 self.type = None
1055 self.optional = optional
1056
1057 def check(self, schema):
1058 assert self.owner
1059 self.type = schema.lookup_type(self._type_name)
1060 assert self.type
1061
1062
Markus Armbrusterac882192015-09-16 13:06:05 +02001063class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001064 def __init__(self, tag_name, tag_member, variants):
1065 # Flat unions pass tag_name but not tag_member.
1066 # Simple unions and alternates pass tag_member but not tag_name.
1067 # After check(), tag_member is always set, and tag_name remains
1068 # a reliable witness of being used by a flat union.
1069 assert bool(tag_member) != bool(tag_name)
1070 assert (isinstance(tag_name, str) or
1071 isinstance(tag_member, QAPISchemaObjectTypeMember))
Eric Blake02a57ae2016-02-17 23:48:16 -07001072 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001073 for v in variants:
1074 assert isinstance(v, QAPISchemaObjectTypeVariant)
1075 self.tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001076 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001077 self.variants = variants
1078
Eric Blake88d4ef82015-11-18 01:52:50 -07001079 def set_owner(self, name):
1080 for v in self.variants:
1081 v.set_owner(name)
1082
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001083 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001084 if not self.tag_member: # flat union
Eric Blake27b60ab2015-11-18 01:52:51 -07001085 self.tag_member = seen[c_name(self.tag_name)]
1086 assert self.tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001087 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1088 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001089 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001090 # Union names must match enum values; alternate names are
1091 # checked separately. Use 'seen' to tell the two apart.
1092 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001093 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001094 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001095 v.type.check(schema)
1096
Eric Blake27b60ab2015-11-18 01:52:51 -07001097 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001098 for v in self.variants:
1099 # Reset seen map for each variant, since qapi names from one
1100 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001101 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001102 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001103
Eric Blake437db252015-09-29 16:21:02 -06001104
Markus Armbrusterac882192015-09-16 13:06:05 +02001105class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001106 role = 'branch'
1107
Markus Armbrusterac882192015-09-16 13:06:05 +02001108 def __init__(self, name, typ):
1109 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1110
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001111 # This function exists to support ugly simple union special cases
1112 # TODO get rid of them, and drop the function
1113 def simple_union_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001114 if (self.type.is_implicit() and
1115 isinstance(self.type, QAPISchemaObjectType)):
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001116 assert len(self.type.members) == 1
1117 assert not self.type.variants
1118 return self.type.members[0].type
1119 return None
1120
Markus Armbrusterac882192015-09-16 13:06:05 +02001121
1122class QAPISchemaAlternateType(QAPISchemaType):
1123 def __init__(self, name, info, variants):
1124 QAPISchemaType.__init__(self, name, info)
1125 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1126 assert not variants.tag_name
Eric Blake88d4ef82015-11-18 01:52:50 -07001127 variants.set_owner(name)
1128 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001129 self.variants = variants
1130
1131 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001132 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001133 # Not calling self.variants.check_clash(), because there's nothing
1134 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001135 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001136 # Alternate branch names have no relation to the tag enum values;
1137 # so we have to check for potential name collisions ourselves.
1138 seen = {}
1139 for v in self.variants.variants:
1140 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001141
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001142 def json_type(self):
1143 return 'value'
1144
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001145 def visit(self, visitor):
1146 visitor.visit_alternate_type(self.name, self.info, self.variants)
1147
Markus Armbrusterac882192015-09-16 13:06:05 +02001148
1149class QAPISchemaCommand(QAPISchemaEntity):
1150 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1151 QAPISchemaEntity.__init__(self, name, info)
1152 assert not arg_type or isinstance(arg_type, str)
1153 assert not ret_type or isinstance(ret_type, str)
1154 self._arg_type_name = arg_type
1155 self.arg_type = None
1156 self._ret_type_name = ret_type
1157 self.ret_type = None
1158 self.gen = gen
1159 self.success_response = success_response
1160
1161 def check(self, schema):
1162 if self._arg_type_name:
1163 self.arg_type = schema.lookup_type(self._arg_type_name)
1164 assert isinstance(self.arg_type, QAPISchemaObjectType)
1165 assert not self.arg_type.variants # not implemented
1166 if self._ret_type_name:
1167 self.ret_type = schema.lookup_type(self._ret_type_name)
1168 assert isinstance(self.ret_type, QAPISchemaType)
1169
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001170 def visit(self, visitor):
1171 visitor.visit_command(self.name, self.info,
1172 self.arg_type, self.ret_type,
1173 self.gen, self.success_response)
1174
Markus Armbrusterac882192015-09-16 13:06:05 +02001175
1176class QAPISchemaEvent(QAPISchemaEntity):
1177 def __init__(self, name, info, arg_type):
1178 QAPISchemaEntity.__init__(self, name, info)
1179 assert not arg_type or isinstance(arg_type, str)
1180 self._arg_type_name = arg_type
1181 self.arg_type = None
1182
1183 def check(self, schema):
1184 if self._arg_type_name:
1185 self.arg_type = schema.lookup_type(self._arg_type_name)
1186 assert isinstance(self.arg_type, QAPISchemaObjectType)
1187 assert not self.arg_type.variants # not implemented
1188
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001189 def visit(self, visitor):
1190 visitor.visit_event(self.name, self.info, self.arg_type)
1191
Markus Armbrusterac882192015-09-16 13:06:05 +02001192
1193class QAPISchema(object):
1194 def __init__(self, fname):
1195 try:
1196 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
Eric Blake7618b912015-10-12 22:22:22 -06001197 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001198 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001199 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001200 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001201 self._def_exprs()
1202 self.check()
Markus Armbruster291928a2015-12-18 08:52:41 +01001203 except (QAPISchemaError, QAPIExprError) as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001204 print >>sys.stderr, err
1205 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001206
Markus Armbrusterac882192015-09-16 13:06:05 +02001207 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001208 # Only the predefined types are allowed to not have info
1209 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001210 assert ent.name not in self._entity_dict
1211 self._entity_dict[ent.name] = ent
1212
1213 def lookup_entity(self, name, typ=None):
1214 ent = self._entity_dict.get(name)
1215 if typ and not isinstance(ent, typ):
1216 return None
1217 return ent
1218
1219 def lookup_type(self, name):
1220 return self.lookup_entity(name, QAPISchemaType)
1221
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001222 def _def_builtin_type(self, name, json_type, c_type, c_null):
1223 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1224 c_type, c_null))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001225 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1226 # qapi-types.h from a single .c, all arrays of builtins must be
1227 # declared in the first file whether or not they are used. Nicer
1228 # would be to use lazy instantiation, while figuring out how to
1229 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001230 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001231
1232 def _def_predefineds(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001233 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1234 ('number', 'number', 'double', '0'),
1235 ('int', 'int', 'int64_t', '0'),
1236 ('int8', 'int', 'int8_t', '0'),
1237 ('int16', 'int', 'int16_t', '0'),
1238 ('int32', 'int', 'int32_t', '0'),
1239 ('int64', 'int', 'int64_t', '0'),
1240 ('uint8', 'int', 'uint8_t', '0'),
1241 ('uint16', 'int', 'uint16_t', '0'),
1242 ('uint32', 'int', 'uint32_t', '0'),
1243 ('uint64', 'int', 'uint64_t', '0'),
1244 ('size', 'int', 'uint64_t', '0'),
1245 ('bool', 'boolean', 'bool', 'false'),
Markus Armbruster28770e02015-09-16 13:06:24 +02001246 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001247 self._def_builtin_type(*t)
Markus Armbruster39a18152015-09-16 13:06:28 +02001248 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1249 [], None)
1250 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001251 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1252 'qstring', 'qdict', 'qlist',
1253 'qfloat', 'qbool'])
1254 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001255 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001256
Eric Blake93bda4d2015-12-01 22:20:55 -07001257 def _make_enum_members(self, values):
1258 return [QAPISchemaMember(v) for v in values]
1259
Eric Blake99df5282015-10-12 22:22:32 -06001260 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001261 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001262 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001263 self._def_entity(QAPISchemaEnumType(
1264 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001265 return name
1266
Eric Blake99df5282015-10-12 22:22:32 -06001267 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001268 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001269 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001270 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001271 return name
1272
Eric Blake99df5282015-10-12 22:22:32 -06001273 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001274 if not members:
1275 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001276 # See also QAPISchemaObjectTypeMember._pretty_owner()
Markus Armbrusterac882192015-09-16 13:06:05 +02001277 name = ':obj-%s-%s' % (name, role)
1278 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001279 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001280 members, None))
1281 return name
1282
1283 def _def_enum_type(self, expr, info):
1284 name = expr['enum']
1285 data = expr['data']
1286 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001287 self._def_entity(QAPISchemaEnumType(
1288 name, info, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001289
Eric Blake99df5282015-10-12 22:22:32 -06001290 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001291 optional = False
1292 if name.startswith('*'):
1293 name = name[1:]
1294 optional = True
1295 if isinstance(typ, list):
1296 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001297 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001298 return QAPISchemaObjectTypeMember(name, typ, optional)
1299
Eric Blake99df5282015-10-12 22:22:32 -06001300 def _make_members(self, data, info):
1301 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001302 for (key, value) in data.iteritems()]
1303
1304 def _def_struct_type(self, expr, info):
1305 name = expr['struct']
1306 base = expr.get('base')
1307 data = expr['data']
1308 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001309 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001310 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001311
1312 def _make_variant(self, case, typ):
1313 return QAPISchemaObjectTypeVariant(case, typ)
1314
Eric Blake99df5282015-10-12 22:22:32 -06001315 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001316 if isinstance(typ, list):
1317 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001318 typ = self._make_array_type(typ[0], info)
1319 typ = self._make_implicit_object_type(
1320 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001321 return QAPISchemaObjectTypeVariant(case, typ)
1322
Markus Armbrusterac882192015-09-16 13:06:05 +02001323 def _def_union_type(self, expr, info):
1324 name = expr['union']
1325 data = expr['data']
1326 base = expr.get('base')
1327 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001328 tag_member = None
Markus Armbrusterac882192015-09-16 13:06:05 +02001329 if tag_name:
1330 variants = [self._make_variant(key, value)
1331 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001332 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001333 else:
Eric Blake99df5282015-10-12 22:22:32 -06001334 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001335 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001336 typ = self._make_implicit_enum_type(name, info,
1337 [v.name for v in variants])
1338 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001339 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001340 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001341 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001342 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001343 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001344 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001345
1346 def _def_alternate_type(self, expr, info):
1347 name = expr['alternate']
1348 data = expr['data']
1349 variants = [self._make_variant(key, value)
1350 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001351 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001352 self._def_entity(
1353 QAPISchemaAlternateType(name, info,
1354 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001355 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001356 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001357
1358 def _def_command(self, expr, info):
1359 name = expr['command']
1360 data = expr.get('data')
1361 rets = expr.get('returns')
1362 gen = expr.get('gen', True)
1363 success_response = expr.get('success-response', True)
1364 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001365 data = self._make_implicit_object_type(
1366 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001367 if isinstance(rets, list):
1368 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001369 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001370 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1371 success_response))
1372
1373 def _def_event(self, expr, info):
1374 name = expr['event']
1375 data = expr.get('data')
1376 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001377 data = self._make_implicit_object_type(
1378 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001379 self._def_entity(QAPISchemaEvent(name, info, data))
1380
1381 def _def_exprs(self):
1382 for expr_elem in self.exprs:
1383 expr = expr_elem['expr']
1384 info = expr_elem['info']
1385 if 'enum' in expr:
1386 self._def_enum_type(expr, info)
1387 elif 'struct' in expr:
1388 self._def_struct_type(expr, info)
1389 elif 'union' in expr:
1390 self._def_union_type(expr, info)
1391 elif 'alternate' in expr:
1392 self._def_alternate_type(expr, info)
1393 elif 'command' in expr:
1394 self._def_command(expr, info)
1395 elif 'event' in expr:
1396 self._def_event(expr, info)
1397 else:
1398 assert False
1399
1400 def check(self):
1401 for ent in self._entity_dict.values():
1402 ent.check(self)
1403
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001404 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001405 visitor.visit_begin(self)
1406 for (name, entity) in sorted(self._entity_dict.items()):
1407 if visitor.visit_needed(entity):
1408 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001409 visitor.visit_end()
1410
Markus Armbruster2caba362013-07-27 17:41:56 +02001411
Markus Armbruster00e4b282015-06-10 10:04:36 +02001412#
1413# Code generation helpers
1414#
1415
Michael Roth0f923be2011-07-19 14:50:39 -05001416def camel_case(name):
1417 new_name = ''
1418 first = True
1419 for ch in name:
1420 if ch in ['_', '-']:
1421 first = True
1422 elif first:
1423 new_name += ch.upper()
1424 first = False
1425 else:
1426 new_name += ch.lower()
1427 return new_name
1428
Eric Blake437db252015-09-29 16:21:02 -06001429
Markus Armbruster849bc532015-05-14 06:50:53 -06001430# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1431# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1432# ENUM24_Name -> ENUM24_NAME
1433def camel_to_upper(value):
1434 c_fun_str = c_name(value, False)
1435 if value.isupper():
1436 return c_fun_str
1437
1438 new_name = ''
1439 l = len(c_fun_str)
1440 for i in range(l):
1441 c = c_fun_str[i]
1442 # When c is upper and no "_" appears before, do more checks
1443 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001444 if i < l - 1 and c_fun_str[i + 1].islower():
1445 new_name += '_'
1446 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001447 new_name += '_'
1448 new_name += c
1449 return new_name.lstrip('_').upper()
1450
Eric Blake437db252015-09-29 16:21:02 -06001451
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001452def c_enum_const(type_name, const_name, prefix=None):
1453 if prefix is not None:
1454 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001455 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001456
Eric Blake18df5152015-05-14 06:50:48 -06001457c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001458
Eric Blake437db252015-09-29 16:21:02 -06001459
Eric Blakec6405b52015-05-14 06:50:55 -06001460# Map @name to a valid C identifier.
1461# If @protect, avoid returning certain ticklish identifiers (like
1462# C keywords) by prepending "q_".
1463#
1464# Used for converting 'name' from a 'name':'type' qapi definition
1465# into a generated struct member, as well as converting type names
1466# into substrings of a generated C function name.
1467# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1468# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001469def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001470 # ANSI X3J11/88-090, 3.1.1
1471 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001472 'default', 'do', 'double', 'else', 'enum', 'extern',
1473 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1474 'return', 'short', 'signed', 'sizeof', 'static',
1475 'struct', 'switch', 'typedef', 'union', 'unsigned',
1476 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001477 # ISO/IEC 9899:1999, 6.4.1
1478 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1479 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001480 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1481 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001482 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1483 # excluding _.*
1484 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001485 # C++ ISO/IEC 14882:2003 2.11
1486 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1487 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1488 'namespace', 'new', 'operator', 'private', 'protected',
1489 'public', 'reinterpret_cast', 'static_cast', 'template',
1490 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1491 'using', 'virtual', 'wchar_t',
1492 # alternative representations
1493 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1494 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001495 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001496 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001497 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001498 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1499 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001500 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001501 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001502
Amos Kong05dfb262014-06-10 19:25:53 +08001503eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001504pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001505
Eric Blake437db252015-09-29 16:21:02 -06001506
Michael Roth0f923be2011-07-19 14:50:39 -05001507def genindent(count):
1508 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001509 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001510 ret += " "
1511 return ret
1512
1513indent_level = 0
1514
Eric Blake437db252015-09-29 16:21:02 -06001515
Michael Roth0f923be2011-07-19 14:50:39 -05001516def push_indent(indent_amount=4):
1517 global indent_level
1518 indent_level += indent_amount
1519
Eric Blake437db252015-09-29 16:21:02 -06001520
Michael Roth0f923be2011-07-19 14:50:39 -05001521def pop_indent(indent_amount=4):
1522 global indent_level
1523 indent_level -= indent_amount
1524
Eric Blake437db252015-09-29 16:21:02 -06001525
Markus Armbruster77e703b2015-06-24 19:27:32 +02001526# Generate @code with @kwds interpolated.
1527# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001528def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001529 raw = code % kwds
1530 if indent_level:
1531 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001532 # re.subn() lacks flags support before Python 2.7, use re.compile()
1533 raw = re.subn(re.compile("^.", re.MULTILINE),
1534 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001535 raw = raw[0]
1536 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001537
Eric Blake437db252015-09-29 16:21:02 -06001538
Michael Roth0f923be2011-07-19 14:50:39 -05001539def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001540 if code[0] == '\n':
1541 code = code[1:]
1542 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001543
Michael Roth0f923be2011-07-19 14:50:39 -05001544
1545def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001546 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001547
Eric Blake437db252015-09-29 16:21:02 -06001548
Michael Rothc0afa9c2013-05-10 17:46:00 -05001549def guardstart(name):
1550 return mcgen('''
1551
1552#ifndef %(name)s
1553#define %(name)s
1554
1555''',
1556 name=guardname(name))
1557
Eric Blake437db252015-09-29 16:21:02 -06001558
Michael Rothc0afa9c2013-05-10 17:46:00 -05001559def guardend(name):
1560 return mcgen('''
1561
1562#endif /* %(name)s */
1563
1564''',
1565 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001566
Eric Blake437db252015-09-29 16:21:02 -06001567
Markus Armbrustere98859a2015-09-16 13:06:16 +02001568def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001569 ret = mcgen('''
1570
Markus Armbrustere98859a2015-09-16 13:06:16 +02001571const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001572''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001573 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001574 for value in values:
1575 index = c_enum_const(name, value, prefix)
1576 ret += mcgen('''
1577 [%(index)s] = "%(value)s",
1578''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001579 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001580
Eric Blake7fb1cf12015-11-18 01:52:57 -07001581 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001582 ret += mcgen('''
1583 [%(max_index)s] = NULL,
1584};
1585''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001586 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001587 return ret
1588
Eric Blake437db252015-09-29 16:21:02 -06001589
Markus Armbrustere98859a2015-09-16 13:06:16 +02001590def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001591 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001592 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001593
1594 ret = mcgen('''
1595
1596typedef enum %(c_name)s {
1597''',
1598 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001599
1600 i = 0
1601 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001602 ret += mcgen('''
1603 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001604''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001605 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001606 i=i)
1607 i += 1
1608
Markus Armbrustere98859a2015-09-16 13:06:16 +02001609 ret += mcgen('''
1610} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001611''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001612 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001613
Markus Armbrustere98859a2015-09-16 13:06:16 +02001614 ret += mcgen('''
1615
1616extern const char *const %(c_name)s_lookup[];
1617''',
1618 c_name=c_name(name))
1619 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001620
Eric Blake437db252015-09-29 16:21:02 -06001621
Markus Armbruster03b43672015-09-16 13:06:20 +02001622def gen_params(arg_type, extra):
1623 if not arg_type:
1624 return extra
1625 assert not arg_type.variants
1626 ret = ''
1627 sep = ''
1628 for memb in arg_type.members:
1629 ret += sep
1630 sep = ', '
1631 if memb.optional:
1632 ret += 'bool has_%s, ' % c_name(memb.name)
1633 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1634 if extra:
1635 ret += sep + extra
1636 return ret
1637
Eric Blake1f353342015-09-29 16:21:13 -06001638
Eric Blake18bdbc32015-09-29 16:21:15 -06001639def gen_err_check(label='out', skiperr=False):
1640 if skiperr:
Eric Blake1f353342015-09-29 16:21:13 -06001641 return ''
1642 return mcgen('''
Eric Blake18bdbc32015-09-29 16:21:15 -06001643 if (err) {
Eric Blake1f353342015-09-29 16:21:13 -06001644 goto %(label)s;
1645 }
1646''',
Eric Blake18bdbc32015-09-29 16:21:15 -06001647 label=label)
Eric Blake1f353342015-09-29 16:21:13 -06001648
1649
Eric Blake14f00c62016-03-03 09:16:43 -07001650def gen_visit_members(members, prefix='', need_cast=False, skiperr=False,
1651 label='out'):
Eric Blake82ca8e42015-09-29 16:21:14 -06001652 ret = ''
Eric Blake18bdbc32015-09-29 16:21:15 -06001653 if skiperr:
Eric Blake82ca8e42015-09-29 16:21:14 -06001654 errparg = 'NULL'
Eric Blake18bdbc32015-09-29 16:21:15 -06001655 else:
1656 errparg = '&err'
Eric Blake82ca8e42015-09-29 16:21:14 -06001657
1658 for memb in members:
1659 if memb.optional:
1660 ret += mcgen('''
Eric Blake51e72bc2016-01-29 06:48:54 -07001661 if (visit_optional(v, "%(name)s", &%(prefix)shas_%(c_name)s)) {
Eric Blake82ca8e42015-09-29 16:21:14 -06001662''',
1663 prefix=prefix, c_name=c_name(memb.name),
Eric Blakee4083112016-01-29 06:48:41 -07001664 name=memb.name)
Eric Blake82ca8e42015-09-29 16:21:14 -06001665 push_indent()
1666
1667 # Ugly: sometimes we need to cast away const
1668 if need_cast and memb.type.name == 'str':
1669 cast = '(char **)'
1670 else:
1671 cast = ''
1672
1673 ret += mcgen('''
Eric Blake51e72bc2016-01-29 06:48:54 -07001674 visit_type_%(c_type)s(v, "%(name)s", %(cast)s&%(prefix)s%(c_name)s, %(errp)s);
Eric Blake82ca8e42015-09-29 16:21:14 -06001675''',
1676 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1677 c_name=c_name(memb.name), name=memb.name,
1678 errp=errparg)
Eric Blakea16e3e52016-01-29 06:48:46 -07001679 ret += gen_err_check(skiperr=skiperr, label=label)
Eric Blake82ca8e42015-09-29 16:21:14 -06001680
1681 if memb.optional:
1682 pop_indent()
1683 ret += mcgen('''
1684 }
1685''')
1686 return ret
1687
1688
Markus Armbruster00e4b282015-06-10 10:04:36 +02001689#
1690# Common command line parsing
1691#
1692
Eric Blake437db252015-09-29 16:21:02 -06001693
1694def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001695
1696 try:
1697 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001698 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001699 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001700 "output-dir="] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001701 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001702 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001703 sys.exit(1)
1704
1705 output_dir = ""
1706 prefix = ""
1707 do_c = False
1708 do_h = False
1709 extra_opts = []
1710
1711 for oa in opts:
1712 o, a = oa
1713 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001714 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1715 if match.end() != len(a):
1716 print >>sys.stderr, \
1717 "%s: 'funny character '%s' in argument of --prefix" \
1718 % (sys.argv[0], a[match.end()])
1719 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001720 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001721 elif o in ("-o", "--output-dir"):
1722 output_dir = a + "/"
1723 elif o in ("-c", "--source"):
1724 do_c = True
1725 elif o in ("-h", "--header"):
1726 do_h = True
1727 else:
1728 extra_opts.append(oa)
1729
1730 if not do_c and not do_h:
1731 do_c = True
1732 do_h = True
1733
Markus Armbruster16d80f62015-04-02 13:32:16 +02001734 if len(args) != 1:
1735 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001736 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001737 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001738
Markus Armbruster54414042015-06-09 16:22:45 +02001739 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001740
Markus Armbruster00e4b282015-06-10 10:04:36 +02001741#
1742# Generate output files with boilerplate
1743#
1744
Eric Blake437db252015-09-29 16:21:02 -06001745
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001746def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1747 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001748 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001749 c_file = output_dir + prefix + c_file
1750 h_file = output_dir + prefix + h_file
1751
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001752 if output_dir:
1753 try:
1754 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01001755 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001756 if e.errno != errno.EEXIST:
1757 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001758
1759 def maybe_open(really, name, opt):
1760 if really:
1761 return open(name, opt)
1762 else:
1763 import StringIO
1764 return StringIO.StringIO()
1765
1766 fdef = maybe_open(do_c, c_file, 'w')
1767 fdecl = maybe_open(do_h, h_file, 'w')
1768
1769 fdef.write(mcgen('''
1770/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1771%(comment)s
1772''',
Eric Blake437db252015-09-29 16:21:02 -06001773 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001774
1775 fdecl.write(mcgen('''
1776/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1777%(comment)s
1778#ifndef %(guard)s
1779#define %(guard)s
1780
1781''',
Eric Blake437db252015-09-29 16:21:02 -06001782 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001783
1784 return (fdef, fdecl)
1785
Eric Blake437db252015-09-29 16:21:02 -06001786
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001787def close_output(fdef, fdecl):
1788 fdecl.write('''
1789#endif
1790''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001791 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001792 fdef.close()