blob: 0635bbb0c3efea94cd2910fd568b2bd88f94ca64 [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
Eric Blake893e1f22015-12-01 22:20:57 -070066 'CpuInfoMIPS', # PC, visible through query-cpu
67 'CpuInfoTricore', # PC, visible through query-cpu
Eric Blake893e1f22015-12-01 22:20:57 -070068 'QapiErrorClass', # all members, visible through errors
69 'UuidInfo', # UUID, visible through query-uuid
70 'X86CPURegister32', # all members, visible indirectly through qom-get
Eric Blake3666a972016-03-17 16:48:40 -060071 'q_obj_CpuInfo-base', # CPU, visible through query-cpu
Eric Blake893e1f22015-12-01 22:20:57 -070072]
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):
Eric Blakeac4338f2016-03-17 16:48:39 -0600330 if isinstance(base, dict):
331 return base
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800332 base_struct_define = find_struct(base)
333 if not base_struct_define:
334 return None
335 return base_struct_define['data']
336
Eric Blake437db252015-09-29 16:21:02 -0600337
Eric Blake811d04f2015-05-04 09:05:10 -0600338# Return the qtype of an alternate branch, or None on error.
339def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600340 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600341 return builtin_types[qapi_type]
342 elif find_struct(qapi_type):
343 return "QTYPE_QDICT"
344 elif find_enum(qapi_type):
345 return "QTYPE_QSTRING"
Eric Blake811d04f2015-05-04 09:05:10 -0600346 elif find_union(qapi_type):
347 return "QTYPE_QDICT"
Eric Blake44bd1272015-05-04 09:05:08 -0600348 return None
349
Eric Blake437db252015-09-29 16:21:02 -0600350
Wenchao Xiabceae762014-03-06 17:08:56 -0800351# Return the discriminator enum define if discriminator is specified as an
352# enum type, otherwise return None.
353def discriminator_find_enum_define(expr):
354 base = expr.get('base')
355 discriminator = expr.get('discriminator')
356
357 if not (discriminator and base):
358 return None
359
Eric Blake14f00c62016-03-03 09:16:43 -0700360 base_members = find_base_members(base)
361 if not base_members:
Wenchao Xiabceae762014-03-06 17:08:56 -0800362 return None
363
Eric Blake14f00c62016-03-03 09:16:43 -0700364 discriminator_type = base_members.get(discriminator)
Wenchao Xiabceae762014-03-06 17:08:56 -0800365 if not discriminator_type:
366 return None
367
368 return find_enum(discriminator_type)
369
Eric Blake437db252015-09-29 16:21:02 -0600370
Eric Blake59a92fe2015-11-18 01:52:56 -0700371# Names must be letters, numbers, -, and _. They must start with letter,
372# except for downstream extensions which must start with __RFQDN_.
373# Dots are only valid in the downstream extension prefix.
374valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
375 '[a-zA-Z][a-zA-Z0-9_-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600376
377
378def check_name(expr_info, source, name, allow_optional=False,
379 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600380 global valid_name
381 membername = name
382
383 if not isinstance(name, str):
384 raise QAPIExprError(expr_info,
385 "%s requires a string name" % source)
386 if name.startswith('*'):
387 membername = name[1:]
388 if not allow_optional:
389 raise QAPIExprError(expr_info,
390 "%s does not allow optional name '%s'"
391 % (source, name))
392 # Enum members can start with a digit, because the generated C
393 # code always prefixes it with the enum name
Eric Blake59a92fe2015-11-18 01:52:56 -0700394 if enum_member and membername[0].isdigit():
395 membername = 'D' + membername
Eric Blake75996972016-03-17 16:48:29 -0600396 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
397 # and 'q_obj_*' implicit type names.
Eric Blake9fb081e2015-10-26 16:34:44 -0600398 if not valid_name.match(membername) or \
399 c_name(membername, False).startswith('q_'):
Eric Blakec9e0a792015-05-04 09:05:22 -0600400 raise QAPIExprError(expr_info,
401 "%s uses invalid name '%s'" % (source, name))
402
Eric Blake437db252015-09-29 16:21:02 -0600403
404def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200405 global all_names
406 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200407 # FIXME should reject names that differ only in '_' vs. '.'
408 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200409 if name in all_names:
410 raise QAPIExprError(info,
411 "%s '%s' is already defined"
412 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600413 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200414 raise QAPIExprError(info,
Eric Blake255960d2015-10-26 16:34:43 -0600415 "%s '%s' should not end in '%s'"
416 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200417 all_names[name] = meta
418
Eric Blake437db252015-09-29 16:21:02 -0600419
Markus Armbruster00e4b282015-06-10 10:04:36 +0200420def add_struct(definition, info):
421 global struct_types
422 name = definition['struct']
423 add_name(name, info, 'struct')
424 struct_types.append(definition)
425
Eric Blake437db252015-09-29 16:21:02 -0600426
Markus Armbruster00e4b282015-06-10 10:04:36 +0200427def find_struct(name):
428 global struct_types
429 for struct in struct_types:
430 if struct['struct'] == name:
431 return struct
432 return None
433
Eric Blake437db252015-09-29 16:21:02 -0600434
Markus Armbruster00e4b282015-06-10 10:04:36 +0200435def add_union(definition, info):
436 global union_types
437 name = definition['union']
438 add_name(name, info, 'union')
439 union_types.append(definition)
440
Eric Blake437db252015-09-29 16:21:02 -0600441
Markus Armbruster00e4b282015-06-10 10:04:36 +0200442def find_union(name):
443 global union_types
444 for union in union_types:
445 if union['union'] == name:
446 return union
447 return None
448
Eric Blake437db252015-09-29 16:21:02 -0600449
450def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200451 global enum_types
452 add_name(name, info, 'enum', implicit)
453 enum_types.append({"enum_name": name, "enum_values": enum_values})
454
Eric Blake437db252015-09-29 16:21:02 -0600455
Markus Armbruster00e4b282015-06-10 10:04:36 +0200456def find_enum(name):
457 global enum_types
458 for enum in enum_types:
459 if enum['enum_name'] == name:
460 return enum
461 return None
462
Markus Armbruster00e4b282015-06-10 10:04:36 +0200463
Eric Blake437db252015-09-29 16:21:02 -0600464def is_enum(name):
465 return find_enum(name) is not None
466
467
468def check_type(expr_info, source, value, allow_array=False,
469 allow_dict=False, allow_optional=False,
470 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600471 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600472
473 if value is None:
474 return
475
Eric Blakedd883c62015-05-04 09:05:21 -0600476 # Check if array type for value is okay
477 if isinstance(value, list):
478 if not allow_array:
479 raise QAPIExprError(expr_info,
480 "%s cannot be an array" % source)
481 if len(value) != 1 or not isinstance(value[0], str):
482 raise QAPIExprError(expr_info,
483 "%s: array type must contain single type name"
484 % source)
485 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600486
487 # Check if type name for value is okay
488 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600489 if value not in all_names:
Eric Blakedd883c62015-05-04 09:05:21 -0600490 raise QAPIExprError(expr_info,
491 "%s uses unknown type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200492 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600493 if not all_names[value] in allow_metas:
494 raise QAPIExprError(expr_info,
495 "%s cannot use %s type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200496 % (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600497 return
498
Eric Blakedd883c62015-05-04 09:05:21 -0600499 if not allow_dict:
500 raise QAPIExprError(expr_info,
501 "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200502
503 if not isinstance(value, OrderedDict):
504 raise QAPIExprError(expr_info,
505 "%s should be a dictionary or type name" % source)
506
507 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600508 for (key, arg) in value.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600509 check_name(expr_info, "Member of %s" % source, key,
510 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600511 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Eric Blake9fb081e2015-10-26 16:34:44 -0600512 raise QAPIExprError(expr_info,
513 "Member of %s uses reserved name '%s'"
514 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600515 # Todo: allow dictionaries to represent default values of
516 # an optional argument.
Eric Blakedd883c62015-05-04 09:05:21 -0600517 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200518 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600519 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600520 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600521
Eric Blake437db252015-09-29 16:21:02 -0600522
Eric Blakedd883c62015-05-04 09:05:21 -0600523def check_command(expr, expr_info):
524 name = expr['command']
Eric Blake2cbf0992015-05-04 09:05:24 -0600525
Eric Blakedd883c62015-05-04 09:05:21 -0600526 check_type(expr_info, "'data' for command '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600527 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200528 allow_metas=['struct'])
Eric Blake10d4d992015-05-04 09:05:23 -0600529 returns_meta = ['union', 'struct']
530 if name in returns_whitelist:
531 returns_meta += ['built-in', 'alternate', 'enum']
Eric Blakedd883c62015-05-04 09:05:21 -0600532 check_type(expr_info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200533 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200534 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600535
Eric Blake437db252015-09-29 16:21:02 -0600536
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200537def check_event(expr, expr_info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600538 global events
539 name = expr['event']
Eric Blake4dc2e692015-05-04 09:05:17 -0600540
Eric Blake4dc2e692015-05-04 09:05:17 -0600541 events.append(name)
Eric Blakedd883c62015-05-04 09:05:21 -0600542 check_type(expr_info, "'data' for event '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600543 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster315932b2015-07-01 10:12:24 +0200544 allow_metas=['struct'])
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200545
Eric Blake437db252015-09-29 16:21:02 -0600546
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800547def check_union(expr, expr_info):
548 name = expr['union']
549 base = expr.get('base')
550 discriminator = expr.get('discriminator')
551 members = expr['data']
552
Eric Blake811d04f2015-05-04 09:05:10 -0600553 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600554
555 # With no discriminator it is a simple union.
556 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600557 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600558 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600559 if base is not None:
560 raise QAPIExprError(expr_info,
Eric Blake811d04f2015-05-04 09:05:10 -0600561 "Simple union '%s' must not have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600562 % name)
563
564 # Else, it's a flat union.
565 else:
Eric Blakeac4338f2016-03-17 16:48:39 -0600566 # The object must have a string or dictionary 'base'.
Eric Blake376863e2015-09-29 16:21:07 -0600567 check_type(expr_info, "'base' for union '%s'" % name,
Eric Blakeac4338f2016-03-17 16:48:39 -0600568 base, allow_dict=True, allow_optional=True,
569 allow_metas=['struct'])
Eric Blake376863e2015-09-29 16:21:07 -0600570 if not base:
Eric Blake44bd1272015-05-04 09:05:08 -0600571 raise QAPIExprError(expr_info,
Eric Blake376863e2015-09-29 16:21:07 -0600572 "Flat union '%s' must have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600573 % name)
Eric Blake14f00c62016-03-03 09:16:43 -0700574 base_members = find_base_members(base)
575 assert base_members
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800576
Eric Blakec9e0a792015-05-04 09:05:22 -0600577 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600578 # member of the base struct.
Eric Blakec9e0a792015-05-04 09:05:22 -0600579 check_name(expr_info, "Discriminator of flat union '%s'" % name,
580 discriminator)
Eric Blake14f00c62016-03-03 09:16:43 -0700581 discriminator_type = base_members.get(discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800582 if not discriminator_type:
583 raise QAPIExprError(expr_info,
584 "Discriminator '%s' is not a member of base "
Eric Blakefd41dd42015-05-04 09:05:25 -0600585 "struct '%s'"
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800586 % (discriminator, base))
587 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600588 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800589 # Do not allow string discriminator
590 if not enum_define:
591 raise QAPIExprError(expr_info,
592 "Discriminator '%s' must be of enumeration "
593 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800594
Eric Blake02a57ae2016-02-17 23:48:16 -0700595 # Check every branch; don't allow an empty union
596 if len(members) == 0:
597 raise QAPIExprError(expr_info,
598 "Union '%s' cannot have empty 'data'" % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800599 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600600 check_name(expr_info, "Member of union '%s'" % name, key)
601
Eric Blake01cfbaa2015-12-01 22:20:58 -0700602 # Each value must name a known type
Eric Blakedd883c62015-05-04 09:05:21 -0600603 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200604 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakedd883c62015-05-04 09:05:21 -0600605
Eric Blake44bd1272015-05-04 09:05:08 -0600606 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700607 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600608 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600609 if key not in enum_define['enum_values']:
Eric Blake44bd1272015-05-04 09:05:08 -0600610 raise QAPIExprError(expr_info,
611 "Discriminator value '%s' is not found in "
612 "enum '%s'" %
613 (key, enum_define["enum_name"]))
614
Eric Blaked0b18232016-07-13 21:50:13 -0600615 # If discriminator is user-defined, ensure all values are covered
616 if enum_define:
617 for value in enum_define['enum_values']:
618 if value not in members.keys():
619 raise QAPIExprError(expr_info,
620 "Union '%s' data missing '%s' branch"
621 % (name, value))
622
Eric Blake437db252015-09-29 16:21:02 -0600623
Eric Blake811d04f2015-05-04 09:05:10 -0600624def check_alternate(expr, expr_info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600625 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600626 members = expr['data']
Eric Blake811d04f2015-05-04 09:05:10 -0600627 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600628
Eric Blake02a57ae2016-02-17 23:48:16 -0700629 # Check every branch; require at least two branches
630 if len(members) < 2:
631 raise QAPIExprError(expr_info,
632 "Alternate '%s' should have at least two branches "
633 "in 'data'" % name)
Eric Blake811d04f2015-05-04 09:05:10 -0600634 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600635 check_name(expr_info, "Member of alternate '%s'" % name, key)
636
Eric Blake811d04f2015-05-04 09:05:10 -0600637 # Ensure alternates have no type conflicts.
Eric Blakedd883c62015-05-04 09:05:21 -0600638 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
639 value,
640 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600641 qtype = find_alternate_member_qtype(value)
Eric Blake46534302016-02-17 23:48:17 -0700642 if not qtype:
643 raise QAPIExprError(expr_info,
644 "Alternate '%s' member '%s' cannot use "
645 "type '%s'" % (name, key, value))
Eric Blake811d04f2015-05-04 09:05:10 -0600646 if qtype in types_seen:
647 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600648 "Alternate '%s' member '%s' can't "
Eric Blake811d04f2015-05-04 09:05:10 -0600649 "be distinguished from member '%s'"
650 % (name, key, types_seen[qtype]))
651 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800652
Eric Blake437db252015-09-29 16:21:02 -0600653
Eric Blakecf393592015-05-04 09:05:04 -0600654def check_enum(expr, expr_info):
655 name = expr['enum']
656 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100657 prefix = expr.get('prefix')
Eric Blakecf393592015-05-04 09:05:04 -0600658
659 if not isinstance(members, list):
660 raise QAPIExprError(expr_info,
661 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100662 if prefix is not None and not isinstance(prefix, str):
663 raise QAPIExprError(expr_info,
664 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600665 for member in members:
Eric Blake437db252015-09-29 16:21:02 -0600666 check_name(expr_info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600667 enum_member=True)
Eric Blakecf393592015-05-04 09:05:04 -0600668
Eric Blake437db252015-09-29 16:21:02 -0600669
Eric Blakedd883c62015-05-04 09:05:21 -0600670def check_struct(expr, expr_info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600671 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600672 members = expr['data']
673
Eric Blakefd41dd42015-05-04 09:05:25 -0600674 check_type(expr_info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600675 allow_dict=True, allow_optional=True)
Eric Blakefd41dd42015-05-04 09:05:25 -0600676 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600677 allow_metas=['struct'])
678
Eric Blake437db252015-09-29 16:21:02 -0600679
Eric Blake0545f6b2015-05-04 09:05:15 -0600680def check_keys(expr_elem, meta, required, optional=[]):
681 expr = expr_elem['expr']
682 info = expr_elem['info']
683 name = expr[meta]
684 if not isinstance(name, str):
685 raise QAPIExprError(info,
686 "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600687 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600688 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600689 if key not in required and key not in optional:
Eric Blake0545f6b2015-05-04 09:05:15 -0600690 raise QAPIExprError(info,
691 "Unknown key '%s' in %s '%s'"
692 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600693 if (key == 'gen' or key == 'success-response') and value is not False:
Eric Blake2cbf0992015-05-04 09:05:24 -0600694 raise QAPIExprError(info,
695 "'%s' of %s '%s' should only use false value"
696 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600697 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600698 if key not in expr:
Eric Blake0545f6b2015-05-04 09:05:15 -0600699 raise QAPIExprError(info,
700 "Key '%s' is missing from %s '%s'"
701 % (key, meta, name))
702
Eric Blake437db252015-09-29 16:21:02 -0600703
Markus Armbruster4d076d62015-06-10 08:55:21 +0200704def check_exprs(exprs):
705 global all_names
706
707 # Learn the types and check for valid expression keys
708 for builtin in builtin_types.keys():
709 all_names[builtin] = 'built-in'
710 for expr_elem in exprs:
711 expr = expr_elem['expr']
712 info = expr_elem['info']
Eric Blake437db252015-09-29 16:21:02 -0600713 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100714 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200715 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600716 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200717 check_keys(expr_elem, 'union', ['data'],
718 ['base', 'discriminator'])
719 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600720 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200721 check_keys(expr_elem, 'alternate', ['data'])
722 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600723 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200724 check_keys(expr_elem, 'struct', ['data'], ['base'])
725 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600726 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200727 check_keys(expr_elem, 'command', [],
728 ['data', 'returns', 'gen', 'success-response'])
729 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600730 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200731 check_keys(expr_elem, 'event', [], ['data'])
732 add_name(expr['event'], info, 'event')
733 else:
734 raise QAPIExprError(expr_elem['info'],
735 "Expression is missing metatype")
736
737 # Try again for hidden UnionKind enum
738 for expr_elem in exprs:
739 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600740 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200741 if not discriminator_find_enum_define(expr):
742 add_enum('%sKind' % expr['union'], expr_elem['info'],
743 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600744 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200745 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
746 implicit=True)
747
748 # Validate that exprs make sense
749 for expr_elem in exprs:
750 expr = expr_elem['expr']
751 info = expr_elem['info']
752
Eric Blake437db252015-09-29 16:21:02 -0600753 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200754 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600755 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200756 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600757 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200758 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600759 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200760 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600761 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200762 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600763 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200764 check_event(expr, info)
765 else:
766 assert False, 'unexpected meta type'
767
Markus Armbrusterac882192015-09-16 13:06:05 +0200768 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600769
Markus Armbrusterac882192015-09-16 13:06:05 +0200770
771#
772# Schema compiler frontend
773#
774
775class QAPISchemaEntity(object):
776 def __init__(self, name, info):
777 assert isinstance(name, str)
778 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -0600779 # For explicitly defined entities, info points to the (explicit)
780 # definition. For builtins (and their arrays), info is None.
781 # For implicitly defined entities, info points to a place that
782 # triggered the implicit definition (there may be more than one
783 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +0200784 self.info = info
785
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200786 def c_name(self):
787 return c_name(self.name)
788
Markus Armbrusterac882192015-09-16 13:06:05 +0200789 def check(self, schema):
790 pass
791
Eric Blake49823c42015-10-12 22:22:27 -0600792 def is_implicit(self):
793 return not self.info
794
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200795 def visit(self, visitor):
796 pass
797
798
799class QAPISchemaVisitor(object):
800 def visit_begin(self, schema):
801 pass
802
803 def visit_end(self):
804 pass
805
Eric Blake25a0d9c2015-10-12 22:22:21 -0600806 def visit_needed(self, entity):
807 # Default to visiting everything
808 return True
809
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200810 def visit_builtin_type(self, name, info, json_type):
811 pass
812
813 def visit_enum_type(self, name, info, values, prefix):
814 pass
815
816 def visit_array_type(self, name, info, element_type):
817 pass
818
819 def visit_object_type(self, name, info, base, members, variants):
820 pass
821
Markus Armbruster39a18152015-09-16 13:06:28 +0200822 def visit_object_type_flat(self, name, info, members, variants):
823 pass
824
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200825 def visit_alternate_type(self, name, info, variants):
826 pass
827
828 def visit_command(self, name, info, arg_type, ret_type,
829 gen, success_response):
830 pass
831
832 def visit_event(self, name, info, arg_type):
833 pass
834
Markus Armbrusterac882192015-09-16 13:06:05 +0200835
836class QAPISchemaType(QAPISchemaEntity):
Eric Blake4040d992016-03-17 16:48:28 -0600837 # Return the C type for common use.
838 # For the types we commonly box, this is a pointer type.
839 def c_type(self):
840 pass
841
842 # Return the C type to be used in a parameter list.
843 def c_param_type(self):
844 return self.c_type()
845
846 # Return the C type to be used where we suppress boxing.
847 def c_unboxed_type(self):
848 return self.c_type()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200849
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200850 def json_type(self):
851 pass
852
853 def alternate_qtype(self):
854 json2qtype = {
855 'string': 'QTYPE_QSTRING',
856 'number': 'QTYPE_QFLOAT',
857 'int': 'QTYPE_QINT',
858 'boolean': 'QTYPE_QBOOL',
859 'object': 'QTYPE_QDICT'
860 }
861 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +0200862
863
864class QAPISchemaBuiltinType(QAPISchemaType):
Eric Blake861877a2016-03-17 16:48:36 -0600865 def __init__(self, name, json_type, c_type):
Markus Armbrusterac882192015-09-16 13:06:05 +0200866 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200867 assert not c_type or isinstance(c_type, str)
868 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
869 'value')
870 self._json_type_name = json_type
871 self._c_type_name = c_type
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200872
873 def c_name(self):
874 return self.name
875
Eric Blake4040d992016-03-17 16:48:28 -0600876 def c_type(self):
877 return self._c_type_name
878
879 def c_param_type(self):
880 if self.name == 'str':
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200881 return 'const ' + self._c_type_name
882 return self._c_type_name
883
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200884 def json_type(self):
885 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +0200886
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200887 def visit(self, visitor):
888 visitor.visit_builtin_type(self.name, self.info, self.json_type())
889
Markus Armbrusterac882192015-09-16 13:06:05 +0200890
891class QAPISchemaEnumType(QAPISchemaType):
892 def __init__(self, name, info, values, prefix):
893 QAPISchemaType.__init__(self, name, info)
894 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -0700895 assert isinstance(v, QAPISchemaMember)
896 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200897 assert prefix is None or isinstance(prefix, str)
898 self.values = values
899 self.prefix = prefix
900
901 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -0700902 seen = {}
903 for v in self.values:
904 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200905
Eric Blake99df5282015-10-12 22:22:32 -0600906 def is_implicit(self):
907 # See QAPISchema._make_implicit_enum_type()
Eric Blake8712fa52015-10-26 16:34:41 -0600908 return self.name.endswith('Kind')
Eric Blake99df5282015-10-12 22:22:32 -0600909
Eric Blake4040d992016-03-17 16:48:28 -0600910 def c_type(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200911 return c_name(self.name)
912
Eric Blake93bda4d2015-12-01 22:20:55 -0700913 def member_names(self):
914 return [v.name for v in self.values]
915
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200916 def json_type(self):
917 return 'string'
918
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200919 def visit(self, visitor):
920 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -0700921 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200922
Markus Armbrusterac882192015-09-16 13:06:05 +0200923
924class QAPISchemaArrayType(QAPISchemaType):
925 def __init__(self, name, info, element_type):
926 QAPISchemaType.__init__(self, name, info)
927 assert isinstance(element_type, str)
928 self._element_type_name = element_type
929 self.element_type = None
930
931 def check(self, schema):
932 self.element_type = schema.lookup_type(self._element_type_name)
933 assert self.element_type
934
Eric Blake99df5282015-10-12 22:22:32 -0600935 def is_implicit(self):
936 return True
937
Eric Blake4040d992016-03-17 16:48:28 -0600938 def c_type(self):
939 return c_name(self.name) + pointer_suffix
940
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200941 def json_type(self):
942 return 'array'
943
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200944 def visit(self, visitor):
945 visitor.visit_array_type(self.name, self.info, self.element_type)
946
Markus Armbrusterac882192015-09-16 13:06:05 +0200947
948class QAPISchemaObjectType(QAPISchemaType):
949 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -0700950 # struct has local_members, optional base, and no variants
951 # flat union has base, variants, and no local_members
952 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +0200953 QAPISchemaType.__init__(self, name, info)
954 assert base is None or isinstance(base, str)
955 for m in local_members:
956 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -0700957 m.set_owner(name)
958 if variants is not None:
959 assert isinstance(variants, QAPISchemaObjectTypeVariants)
960 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200961 self._base_name = base
962 self.base = None
963 self.local_members = local_members
964 self.variants = variants
965 self.members = None
966
967 def check(self, schema):
Eric Blakebac54292015-12-01 22:20:59 -0700968 if self.members is False: # check for cycles
969 raise QAPIExprError(self.info,
970 "Object %s contains itself" % self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200971 if self.members:
972 return
973 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -0700974 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +0200975 if self._base_name:
976 self.base = schema.lookup_type(self._base_name)
977 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +0200978 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700979 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200980 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -0700981 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700982 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700983 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +0200984 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -0700985 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700986 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -0700987 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200988
Eric Blake14f00c62016-03-03 09:16:43 -0700989 # Check that the members of this type do not cause duplicate JSON members,
Eric Blake27b60ab2015-11-18 01:52:51 -0700990 # and update seen to track the members seen so far. Report any errors
991 # on behalf of info, which is not necessarily self.info
992 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -0700993 assert not self.variants # not implemented
994 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -0700995 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -0700996
Eric Blake99df5282015-10-12 22:22:32 -0600997 def is_implicit(self):
Eric Blake75996972016-03-17 16:48:29 -0600998 # See QAPISchema._make_implicit_object_type(), as well as
999 # _def_predefineds()
1000 return self.name.startswith('q_')
Eric Blake99df5282015-10-12 22:22:32 -06001001
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001002 def c_name(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001003 return QAPISchemaType.c_name(self)
1004
Eric Blake4040d992016-03-17 16:48:28 -06001005 def c_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001006 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -07001007 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001008
Eric Blake4040d992016-03-17 16:48:28 -06001009 def c_unboxed_type(self):
Eric Blake4040d992016-03-17 16:48:28 -06001010 return c_name(self.name)
1011
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001012 def json_type(self):
1013 return 'object'
1014
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001015 def visit(self, visitor):
1016 visitor.visit_object_type(self.name, self.info,
1017 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001018 visitor.visit_object_type_flat(self.name, self.info,
1019 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001020
Markus Armbrusterac882192015-09-16 13:06:05 +02001021
Eric Blaked44f9ac2015-12-01 22:20:54 -07001022class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001023 role = 'member'
1024
Eric Blaked44f9ac2015-12-01 22:20:54 -07001025 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001026 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001027 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001028 self.owner = None
1029
1030 def set_owner(self, name):
1031 assert not self.owner
1032 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001033
Eric Blake27b60ab2015-11-18 01:52:51 -07001034 def check_clash(self, info, seen):
1035 cname = c_name(self.name)
Eric Blake893e1f22015-12-01 22:20:57 -07001036 if cname.lower() != cname and self.owner not in case_whitelist:
1037 raise QAPIExprError(info,
1038 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001039 if cname in seen:
1040 raise QAPIExprError(info,
1041 "%s collides with %s"
1042 % (self.describe(), seen[cname].describe()))
1043 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001044
Eric Blake88d4ef82015-11-18 01:52:50 -07001045 def _pretty_owner(self):
1046 owner = self.owner
Eric Blake75996972016-03-17 16:48:29 -06001047 if owner.startswith('q_obj_'):
Eric Blake88d4ef82015-11-18 01:52:50 -07001048 # See QAPISchema._make_implicit_object_type() - reverse the
1049 # mapping there to create a nice human-readable description
Eric Blake75996972016-03-17 16:48:29 -06001050 owner = owner[6:]
Eric Blake88d4ef82015-11-18 01:52:50 -07001051 if owner.endswith('-arg'):
1052 return '(parameter of %s)' % owner[:-4]
Eric Blakeac4338f2016-03-17 16:48:39 -06001053 elif owner.endswith('-base'):
1054 return '(base of %s)' % owner[:-5]
Eric Blake88d4ef82015-11-18 01:52:50 -07001055 else:
1056 assert owner.endswith('-wrapper')
1057 # Unreachable and not implemented
1058 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001059 if owner.endswith('Kind'):
1060 # See QAPISchema._make_implicit_enum_type()
1061 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001062 return '(%s of %s)' % (self.role, owner)
1063
1064 def describe(self):
1065 return "'%s' %s" % (self.name, self._pretty_owner())
1066
Markus Armbrusterac882192015-09-16 13:06:05 +02001067
Eric Blaked44f9ac2015-12-01 22:20:54 -07001068class QAPISchemaObjectTypeMember(QAPISchemaMember):
1069 def __init__(self, name, typ, optional):
1070 QAPISchemaMember.__init__(self, name)
1071 assert isinstance(typ, str)
1072 assert isinstance(optional, bool)
1073 self._type_name = typ
1074 self.type = None
1075 self.optional = optional
1076
1077 def check(self, schema):
1078 assert self.owner
1079 self.type = schema.lookup_type(self._type_name)
1080 assert self.type
1081
1082
Markus Armbrusterac882192015-09-16 13:06:05 +02001083class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001084 def __init__(self, tag_name, tag_member, variants):
1085 # Flat unions pass tag_name but not tag_member.
1086 # Simple unions and alternates pass tag_member but not tag_name.
1087 # After check(), tag_member is always set, and tag_name remains
1088 # a reliable witness of being used by a flat union.
1089 assert bool(tag_member) != bool(tag_name)
1090 assert (isinstance(tag_name, str) or
1091 isinstance(tag_member, QAPISchemaObjectTypeMember))
Eric Blake02a57ae2016-02-17 23:48:16 -07001092 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001093 for v in variants:
1094 assert isinstance(v, QAPISchemaObjectTypeVariant)
1095 self.tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001096 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001097 self.variants = variants
1098
Eric Blake88d4ef82015-11-18 01:52:50 -07001099 def set_owner(self, name):
1100 for v in self.variants:
1101 v.set_owner(name)
1102
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001103 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001104 if not self.tag_member: # flat union
Eric Blake27b60ab2015-11-18 01:52:51 -07001105 self.tag_member = seen[c_name(self.tag_name)]
1106 assert self.tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001107 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1108 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001109 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001110 # Union names must match enum values; alternate names are
1111 # checked separately. Use 'seen' to tell the two apart.
1112 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001113 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001114 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001115 v.type.check(schema)
1116
Eric Blake27b60ab2015-11-18 01:52:51 -07001117 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001118 for v in self.variants:
1119 # Reset seen map for each variant, since qapi names from one
1120 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001121 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001122 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001123
Eric Blake437db252015-09-29 16:21:02 -06001124
Markus Armbrusterac882192015-09-16 13:06:05 +02001125class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001126 role = 'branch'
1127
Markus Armbrusterac882192015-09-16 13:06:05 +02001128 def __init__(self, name, typ):
1129 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1130
Markus Armbrusterac882192015-09-16 13:06:05 +02001131
1132class QAPISchemaAlternateType(QAPISchemaType):
1133 def __init__(self, name, info, variants):
1134 QAPISchemaType.__init__(self, name, info)
1135 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1136 assert not variants.tag_name
Eric Blake88d4ef82015-11-18 01:52:50 -07001137 variants.set_owner(name)
1138 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001139 self.variants = variants
1140
1141 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001142 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001143 # Not calling self.variants.check_clash(), because there's nothing
1144 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001145 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001146 # Alternate branch names have no relation to the tag enum values;
1147 # so we have to check for potential name collisions ourselves.
1148 seen = {}
1149 for v in self.variants.variants:
1150 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001151
Eric Blake4040d992016-03-17 16:48:28 -06001152 def c_type(self):
1153 return c_name(self.name) + pointer_suffix
1154
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001155 def json_type(self):
1156 return 'value'
1157
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001158 def visit(self, visitor):
1159 visitor.visit_alternate_type(self.name, self.info, self.variants)
1160
Markus Armbrusterac882192015-09-16 13:06:05 +02001161
1162class QAPISchemaCommand(QAPISchemaEntity):
1163 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1164 QAPISchemaEntity.__init__(self, name, info)
1165 assert not arg_type or isinstance(arg_type, str)
1166 assert not ret_type or isinstance(ret_type, str)
1167 self._arg_type_name = arg_type
1168 self.arg_type = None
1169 self._ret_type_name = ret_type
1170 self.ret_type = None
1171 self.gen = gen
1172 self.success_response = success_response
1173
1174 def check(self, schema):
1175 if self._arg_type_name:
1176 self.arg_type = schema.lookup_type(self._arg_type_name)
1177 assert isinstance(self.arg_type, QAPISchemaObjectType)
1178 assert not self.arg_type.variants # not implemented
1179 if self._ret_type_name:
1180 self.ret_type = schema.lookup_type(self._ret_type_name)
1181 assert isinstance(self.ret_type, QAPISchemaType)
1182
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001183 def visit(self, visitor):
1184 visitor.visit_command(self.name, self.info,
1185 self.arg_type, self.ret_type,
1186 self.gen, self.success_response)
1187
Markus Armbrusterac882192015-09-16 13:06:05 +02001188
1189class QAPISchemaEvent(QAPISchemaEntity):
1190 def __init__(self, name, info, arg_type):
1191 QAPISchemaEntity.__init__(self, name, info)
1192 assert not arg_type or isinstance(arg_type, str)
1193 self._arg_type_name = arg_type
1194 self.arg_type = None
1195
1196 def check(self, schema):
1197 if self._arg_type_name:
1198 self.arg_type = schema.lookup_type(self._arg_type_name)
1199 assert isinstance(self.arg_type, QAPISchemaObjectType)
1200 assert not self.arg_type.variants # not implemented
1201
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001202 def visit(self, visitor):
1203 visitor.visit_event(self.name, self.info, self.arg_type)
1204
Markus Armbrusterac882192015-09-16 13:06:05 +02001205
1206class QAPISchema(object):
1207 def __init__(self, fname):
1208 try:
1209 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
Eric Blake7618b912015-10-12 22:22:22 -06001210 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001211 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001212 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001213 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001214 self._def_exprs()
1215 self.check()
Markus Armbruster291928a2015-12-18 08:52:41 +01001216 except (QAPISchemaError, QAPIExprError) as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001217 print >>sys.stderr, err
1218 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001219
Markus Armbrusterac882192015-09-16 13:06:05 +02001220 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001221 # Only the predefined types are allowed to not have info
1222 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001223 assert ent.name not in self._entity_dict
1224 self._entity_dict[ent.name] = ent
1225
1226 def lookup_entity(self, name, typ=None):
1227 ent = self._entity_dict.get(name)
1228 if typ and not isinstance(ent, typ):
1229 return None
1230 return ent
1231
1232 def lookup_type(self, name):
1233 return self.lookup_entity(name, QAPISchemaType)
1234
Eric Blake861877a2016-03-17 16:48:36 -06001235 def _def_builtin_type(self, name, json_type, c_type):
1236 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001237 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1238 # qapi-types.h from a single .c, all arrays of builtins must be
1239 # declared in the first file whether or not they are used. Nicer
1240 # would be to use lazy instantiation, while figuring out how to
1241 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001242 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001243
1244 def _def_predefineds(self):
Eric Blake861877a2016-03-17 16:48:36 -06001245 for t in [('str', 'string', 'char' + pointer_suffix),
1246 ('number', 'number', 'double'),
1247 ('int', 'int', 'int64_t'),
1248 ('int8', 'int', 'int8_t'),
1249 ('int16', 'int', 'int16_t'),
1250 ('int32', 'int', 'int32_t'),
1251 ('int64', 'int', 'int64_t'),
1252 ('uint8', 'int', 'uint8_t'),
1253 ('uint16', 'int', 'uint16_t'),
1254 ('uint32', 'int', 'uint32_t'),
1255 ('uint64', 'int', 'uint64_t'),
1256 ('size', 'int', 'uint64_t'),
1257 ('bool', 'boolean', 'bool'),
1258 ('any', 'value', 'QObject' + pointer_suffix)]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001259 self._def_builtin_type(*t)
Eric Blake75996972016-03-17 16:48:29 -06001260 self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1261 None, [], None)
Markus Armbruster39a18152015-09-16 13:06:28 +02001262 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001263 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1264 'qstring', 'qdict', 'qlist',
1265 'qfloat', 'qbool'])
1266 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001267 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001268
Eric Blake93bda4d2015-12-01 22:20:55 -07001269 def _make_enum_members(self, values):
1270 return [QAPISchemaMember(v) for v in values]
1271
Eric Blake99df5282015-10-12 22:22:32 -06001272 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001273 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001274 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001275 self._def_entity(QAPISchemaEnumType(
1276 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001277 return name
1278
Eric Blake99df5282015-10-12 22:22:32 -06001279 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001280 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001281 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001282 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001283 return name
1284
Eric Blake99df5282015-10-12 22:22:32 -06001285 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001286 if not members:
1287 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001288 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake75996972016-03-17 16:48:29 -06001289 name = 'q_obj_%s-%s' % (name, role)
Markus Armbrusterac882192015-09-16 13:06:05 +02001290 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001291 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001292 members, None))
1293 return name
1294
1295 def _def_enum_type(self, expr, info):
1296 name = expr['enum']
1297 data = expr['data']
1298 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001299 self._def_entity(QAPISchemaEnumType(
1300 name, info, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001301
Eric Blake99df5282015-10-12 22:22:32 -06001302 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001303 optional = False
1304 if name.startswith('*'):
1305 name = name[1:]
1306 optional = True
1307 if isinstance(typ, list):
1308 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001309 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001310 return QAPISchemaObjectTypeMember(name, typ, optional)
1311
Eric Blake99df5282015-10-12 22:22:32 -06001312 def _make_members(self, data, info):
1313 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001314 for (key, value) in data.iteritems()]
1315
1316 def _def_struct_type(self, expr, info):
1317 name = expr['struct']
1318 base = expr.get('base')
1319 data = expr['data']
1320 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001321 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001322 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001323
1324 def _make_variant(self, case, typ):
1325 return QAPISchemaObjectTypeVariant(case, typ)
1326
Eric Blake99df5282015-10-12 22:22:32 -06001327 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001328 if isinstance(typ, list):
1329 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001330 typ = self._make_array_type(typ[0], info)
1331 typ = self._make_implicit_object_type(
1332 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001333 return QAPISchemaObjectTypeVariant(case, typ)
1334
Markus Armbrusterac882192015-09-16 13:06:05 +02001335 def _def_union_type(self, expr, info):
1336 name = expr['union']
1337 data = expr['data']
1338 base = expr.get('base')
1339 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001340 tag_member = None
Eric Blakeac4338f2016-03-17 16:48:39 -06001341 if isinstance(base, dict):
1342 base = (self._make_implicit_object_type(
1343 name, info, 'base', self._make_members(base, info)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001344 if tag_name:
1345 variants = [self._make_variant(key, value)
1346 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001347 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001348 else:
Eric Blake99df5282015-10-12 22:22:32 -06001349 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001350 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001351 typ = self._make_implicit_enum_type(name, info,
1352 [v.name for v in variants])
1353 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001354 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001355 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001356 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001357 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001358 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001359 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001360
1361 def _def_alternate_type(self, expr, info):
1362 name = expr['alternate']
1363 data = expr['data']
1364 variants = [self._make_variant(key, value)
1365 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001366 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001367 self._def_entity(
1368 QAPISchemaAlternateType(name, info,
1369 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001370 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001371 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001372
1373 def _def_command(self, expr, info):
1374 name = expr['command']
1375 data = expr.get('data')
1376 rets = expr.get('returns')
1377 gen = expr.get('gen', True)
1378 success_response = expr.get('success-response', True)
1379 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001380 data = self._make_implicit_object_type(
1381 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001382 if isinstance(rets, list):
1383 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001384 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001385 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1386 success_response))
1387
1388 def _def_event(self, expr, info):
1389 name = expr['event']
1390 data = expr.get('data')
1391 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001392 data = self._make_implicit_object_type(
1393 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001394 self._def_entity(QAPISchemaEvent(name, info, data))
1395
1396 def _def_exprs(self):
1397 for expr_elem in self.exprs:
1398 expr = expr_elem['expr']
1399 info = expr_elem['info']
1400 if 'enum' in expr:
1401 self._def_enum_type(expr, info)
1402 elif 'struct' in expr:
1403 self._def_struct_type(expr, info)
1404 elif 'union' in expr:
1405 self._def_union_type(expr, info)
1406 elif 'alternate' in expr:
1407 self._def_alternate_type(expr, info)
1408 elif 'command' in expr:
1409 self._def_command(expr, info)
1410 elif 'event' in expr:
1411 self._def_event(expr, info)
1412 else:
1413 assert False
1414
1415 def check(self):
1416 for ent in self._entity_dict.values():
1417 ent.check(self)
1418
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001419 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001420 visitor.visit_begin(self)
1421 for (name, entity) in sorted(self._entity_dict.items()):
1422 if visitor.visit_needed(entity):
1423 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001424 visitor.visit_end()
1425
Markus Armbruster2caba362013-07-27 17:41:56 +02001426
Markus Armbruster00e4b282015-06-10 10:04:36 +02001427#
1428# Code generation helpers
1429#
1430
Michael Roth0f923be2011-07-19 14:50:39 -05001431def camel_case(name):
1432 new_name = ''
1433 first = True
1434 for ch in name:
1435 if ch in ['_', '-']:
1436 first = True
1437 elif first:
1438 new_name += ch.upper()
1439 first = False
1440 else:
1441 new_name += ch.lower()
1442 return new_name
1443
Eric Blake437db252015-09-29 16:21:02 -06001444
Markus Armbruster849bc532015-05-14 06:50:53 -06001445# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1446# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1447# ENUM24_Name -> ENUM24_NAME
1448def camel_to_upper(value):
1449 c_fun_str = c_name(value, False)
1450 if value.isupper():
1451 return c_fun_str
1452
1453 new_name = ''
1454 l = len(c_fun_str)
1455 for i in range(l):
1456 c = c_fun_str[i]
1457 # When c is upper and no "_" appears before, do more checks
1458 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001459 if i < l - 1 and c_fun_str[i + 1].islower():
1460 new_name += '_'
1461 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001462 new_name += '_'
1463 new_name += c
1464 return new_name.lstrip('_').upper()
1465
Eric Blake437db252015-09-29 16:21:02 -06001466
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001467def c_enum_const(type_name, const_name, prefix=None):
1468 if prefix is not None:
1469 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001470 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001471
Eric Blake18df5152015-05-14 06:50:48 -06001472c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001473
Eric Blake437db252015-09-29 16:21:02 -06001474
Eric Blakec6405b52015-05-14 06:50:55 -06001475# Map @name to a valid C identifier.
1476# If @protect, avoid returning certain ticklish identifiers (like
1477# C keywords) by prepending "q_".
1478#
1479# Used for converting 'name' from a 'name':'type' qapi definition
1480# into a generated struct member, as well as converting type names
1481# into substrings of a generated C function name.
1482# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1483# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001484def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001485 # ANSI X3J11/88-090, 3.1.1
1486 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001487 'default', 'do', 'double', 'else', 'enum', 'extern',
1488 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1489 'return', 'short', 'signed', 'sizeof', 'static',
1490 'struct', 'switch', 'typedef', 'union', 'unsigned',
1491 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001492 # ISO/IEC 9899:1999, 6.4.1
1493 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1494 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001495 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1496 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001497 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1498 # excluding _.*
1499 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001500 # C++ ISO/IEC 14882:2003 2.11
1501 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1502 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1503 'namespace', 'new', 'operator', 'private', 'protected',
1504 'public', 'reinterpret_cast', 'static_cast', 'template',
1505 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1506 'using', 'virtual', 'wchar_t',
1507 # alternative representations
1508 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1509 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001510 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001511 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001512 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001513 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1514 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001515 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001516 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001517
Amos Kong05dfb262014-06-10 19:25:53 +08001518eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001519pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001520
Eric Blake437db252015-09-29 16:21:02 -06001521
Michael Roth0f923be2011-07-19 14:50:39 -05001522def genindent(count):
1523 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001524 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001525 ret += " "
1526 return ret
1527
1528indent_level = 0
1529
Eric Blake437db252015-09-29 16:21:02 -06001530
Michael Roth0f923be2011-07-19 14:50:39 -05001531def push_indent(indent_amount=4):
1532 global indent_level
1533 indent_level += indent_amount
1534
Eric Blake437db252015-09-29 16:21:02 -06001535
Michael Roth0f923be2011-07-19 14:50:39 -05001536def pop_indent(indent_amount=4):
1537 global indent_level
1538 indent_level -= indent_amount
1539
Eric Blake437db252015-09-29 16:21:02 -06001540
Markus Armbruster77e703b2015-06-24 19:27:32 +02001541# Generate @code with @kwds interpolated.
1542# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001543def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001544 raw = code % kwds
1545 if indent_level:
1546 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001547 # re.subn() lacks flags support before Python 2.7, use re.compile()
1548 raw = re.subn(re.compile("^.", re.MULTILINE),
1549 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001550 raw = raw[0]
1551 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001552
Eric Blake437db252015-09-29 16:21:02 -06001553
Michael Roth0f923be2011-07-19 14:50:39 -05001554def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001555 if code[0] == '\n':
1556 code = code[1:]
1557 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001558
Michael Roth0f923be2011-07-19 14:50:39 -05001559
1560def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001561 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001562
Eric Blake437db252015-09-29 16:21:02 -06001563
Michael Rothc0afa9c2013-05-10 17:46:00 -05001564def guardstart(name):
1565 return mcgen('''
1566
1567#ifndef %(name)s
1568#define %(name)s
1569
1570''',
1571 name=guardname(name))
1572
Eric Blake437db252015-09-29 16:21:02 -06001573
Michael Rothc0afa9c2013-05-10 17:46:00 -05001574def guardend(name):
1575 return mcgen('''
1576
1577#endif /* %(name)s */
1578
1579''',
1580 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001581
Eric Blake437db252015-09-29 16:21:02 -06001582
Markus Armbrustere98859a2015-09-16 13:06:16 +02001583def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001584 ret = mcgen('''
1585
Markus Armbrustere98859a2015-09-16 13:06:16 +02001586const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001587''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001588 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001589 for value in values:
1590 index = c_enum_const(name, value, prefix)
1591 ret += mcgen('''
1592 [%(index)s] = "%(value)s",
1593''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001594 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001595
Eric Blake7fb1cf12015-11-18 01:52:57 -07001596 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001597 ret += mcgen('''
1598 [%(max_index)s] = NULL,
1599};
1600''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001601 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001602 return ret
1603
Eric Blake437db252015-09-29 16:21:02 -06001604
Markus Armbrustere98859a2015-09-16 13:06:16 +02001605def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001606 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001607 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001608
1609 ret = mcgen('''
1610
1611typedef enum %(c_name)s {
1612''',
1613 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001614
1615 i = 0
1616 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001617 ret += mcgen('''
1618 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001619''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001620 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001621 i=i)
1622 i += 1
1623
Markus Armbrustere98859a2015-09-16 13:06:16 +02001624 ret += mcgen('''
1625} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001626''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001627 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001628
Markus Armbrustere98859a2015-09-16 13:06:16 +02001629 ret += mcgen('''
1630
1631extern const char *const %(c_name)s_lookup[];
1632''',
1633 c_name=c_name(name))
1634 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001635
Eric Blake437db252015-09-29 16:21:02 -06001636
Markus Armbruster03b43672015-09-16 13:06:20 +02001637def gen_params(arg_type, extra):
1638 if not arg_type:
1639 return extra
1640 assert not arg_type.variants
1641 ret = ''
1642 sep = ''
1643 for memb in arg_type.members:
1644 ret += sep
1645 sep = ', '
1646 if memb.optional:
1647 ret += 'bool has_%s, ' % c_name(memb.name)
Eric Blake4040d992016-03-17 16:48:28 -06001648 ret += '%s %s' % (memb.type.c_param_type(), c_name(memb.name))
Markus Armbruster03b43672015-09-16 13:06:20 +02001649 if extra:
1650 ret += sep + extra
1651 return ret
1652
Eric Blake1f353342015-09-29 16:21:13 -06001653
Eric Blake12f254f2016-03-17 16:48:35 -06001654def gen_err_check():
Eric Blake1f353342015-09-29 16:21:13 -06001655 return mcgen('''
Eric Blake18bdbc32015-09-29 16:21:15 -06001656 if (err) {
Eric Blake12f254f2016-03-17 16:48:35 -06001657 goto out;
Eric Blake82ca8e42015-09-29 16:21:14 -06001658 }
1659''')
Eric Blake82ca8e42015-09-29 16:21:14 -06001660
1661
Markus Armbruster00e4b282015-06-10 10:04:36 +02001662#
1663# Common command line parsing
1664#
1665
Eric Blake437db252015-09-29 16:21:02 -06001666
1667def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001668
1669 try:
1670 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001671 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001672 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001673 "output-dir="] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001674 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001675 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001676 sys.exit(1)
1677
1678 output_dir = ""
1679 prefix = ""
1680 do_c = False
1681 do_h = False
1682 extra_opts = []
1683
1684 for oa in opts:
1685 o, a = oa
1686 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001687 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1688 if match.end() != len(a):
1689 print >>sys.stderr, \
1690 "%s: 'funny character '%s' in argument of --prefix" \
1691 % (sys.argv[0], a[match.end()])
1692 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001693 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001694 elif o in ("-o", "--output-dir"):
1695 output_dir = a + "/"
1696 elif o in ("-c", "--source"):
1697 do_c = True
1698 elif o in ("-h", "--header"):
1699 do_h = True
1700 else:
1701 extra_opts.append(oa)
1702
1703 if not do_c and not do_h:
1704 do_c = True
1705 do_h = True
1706
Markus Armbruster16d80f62015-04-02 13:32:16 +02001707 if len(args) != 1:
1708 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001709 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001710 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001711
Markus Armbruster54414042015-06-09 16:22:45 +02001712 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001713
Markus Armbruster00e4b282015-06-10 10:04:36 +02001714#
1715# Generate output files with boilerplate
1716#
1717
Eric Blake437db252015-09-29 16:21:02 -06001718
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001719def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1720 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001721 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001722 c_file = output_dir + prefix + c_file
1723 h_file = output_dir + prefix + h_file
1724
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001725 if output_dir:
1726 try:
1727 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01001728 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001729 if e.errno != errno.EEXIST:
1730 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001731
1732 def maybe_open(really, name, opt):
1733 if really:
1734 return open(name, opt)
1735 else:
1736 import StringIO
1737 return StringIO.StringIO()
1738
1739 fdef = maybe_open(do_c, c_file, 'w')
1740 fdecl = maybe_open(do_h, h_file, 'w')
1741
1742 fdef.write(mcgen('''
1743/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1744%(comment)s
1745''',
Eric Blake437db252015-09-29 16:21:02 -06001746 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001747
1748 fdecl.write(mcgen('''
1749/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1750%(comment)s
1751#ifndef %(guard)s
1752#define %(guard)s
1753
1754''',
Eric Blake437db252015-09-29 16:21:02 -06001755 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001756
1757 return (fdef, fdecl)
1758
Eric Blake437db252015-09-29 16:21:02 -06001759
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001760def close_output(fdef, fdecl):
1761 fdecl.write('''
1762#endif
1763''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001764 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001765 fdef.close()