blob: 27284be1443a82175f77f029742579ca2b77648e [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
Eric Blakeb6167702016-07-13 21:50:16 -06001002 def is_empty(self):
1003 assert self.members is not None
1004 return not self.members and not self.variants
1005
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001006 def c_name(self):
Eric Blakecd50a252016-07-13 21:50:14 -06001007 assert self.name != 'q_empty'
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001008 return QAPISchemaType.c_name(self)
1009
Eric Blake4040d992016-03-17 16:48:28 -06001010 def c_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001011 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -07001012 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001013
Eric Blake4040d992016-03-17 16:48:28 -06001014 def c_unboxed_type(self):
Eric Blake4040d992016-03-17 16:48:28 -06001015 return c_name(self.name)
1016
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001017 def json_type(self):
1018 return 'object'
1019
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001020 def visit(self, visitor):
1021 visitor.visit_object_type(self.name, self.info,
1022 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001023 visitor.visit_object_type_flat(self.name, self.info,
1024 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001025
Markus Armbrusterac882192015-09-16 13:06:05 +02001026
Eric Blaked44f9ac2015-12-01 22:20:54 -07001027class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001028 role = 'member'
1029
Eric Blaked44f9ac2015-12-01 22:20:54 -07001030 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001031 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001032 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001033 self.owner = None
1034
1035 def set_owner(self, name):
1036 assert not self.owner
1037 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001038
Eric Blake27b60ab2015-11-18 01:52:51 -07001039 def check_clash(self, info, seen):
1040 cname = c_name(self.name)
Eric Blake893e1f22015-12-01 22:20:57 -07001041 if cname.lower() != cname and self.owner not in case_whitelist:
1042 raise QAPIExprError(info,
1043 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001044 if cname in seen:
1045 raise QAPIExprError(info,
1046 "%s collides with %s"
1047 % (self.describe(), seen[cname].describe()))
1048 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001049
Eric Blake88d4ef82015-11-18 01:52:50 -07001050 def _pretty_owner(self):
1051 owner = self.owner
Eric Blake75996972016-03-17 16:48:29 -06001052 if owner.startswith('q_obj_'):
Eric Blake88d4ef82015-11-18 01:52:50 -07001053 # See QAPISchema._make_implicit_object_type() - reverse the
1054 # mapping there to create a nice human-readable description
Eric Blake75996972016-03-17 16:48:29 -06001055 owner = owner[6:]
Eric Blake88d4ef82015-11-18 01:52:50 -07001056 if owner.endswith('-arg'):
1057 return '(parameter of %s)' % owner[:-4]
Eric Blakeac4338f2016-03-17 16:48:39 -06001058 elif owner.endswith('-base'):
1059 return '(base of %s)' % owner[:-5]
Eric Blake88d4ef82015-11-18 01:52:50 -07001060 else:
1061 assert owner.endswith('-wrapper')
1062 # Unreachable and not implemented
1063 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001064 if owner.endswith('Kind'):
1065 # See QAPISchema._make_implicit_enum_type()
1066 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001067 return '(%s of %s)' % (self.role, owner)
1068
1069 def describe(self):
1070 return "'%s' %s" % (self.name, self._pretty_owner())
1071
Markus Armbrusterac882192015-09-16 13:06:05 +02001072
Eric Blaked44f9ac2015-12-01 22:20:54 -07001073class QAPISchemaObjectTypeMember(QAPISchemaMember):
1074 def __init__(self, name, typ, optional):
1075 QAPISchemaMember.__init__(self, name)
1076 assert isinstance(typ, str)
1077 assert isinstance(optional, bool)
1078 self._type_name = typ
1079 self.type = None
1080 self.optional = optional
1081
1082 def check(self, schema):
1083 assert self.owner
1084 self.type = schema.lookup_type(self._type_name)
1085 assert self.type
1086
1087
Markus Armbrusterac882192015-09-16 13:06:05 +02001088class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001089 def __init__(self, tag_name, tag_member, variants):
1090 # Flat unions pass tag_name but not tag_member.
1091 # Simple unions and alternates pass tag_member but not tag_name.
1092 # After check(), tag_member is always set, and tag_name remains
1093 # a reliable witness of being used by a flat union.
1094 assert bool(tag_member) != bool(tag_name)
1095 assert (isinstance(tag_name, str) or
1096 isinstance(tag_member, QAPISchemaObjectTypeMember))
Eric Blake02a57ae2016-02-17 23:48:16 -07001097 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001098 for v in variants:
1099 assert isinstance(v, QAPISchemaObjectTypeVariant)
Eric Blakeda9cb192016-07-13 21:50:15 -06001100 self._tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001101 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001102 self.variants = variants
1103
Eric Blake88d4ef82015-11-18 01:52:50 -07001104 def set_owner(self, name):
1105 for v in self.variants:
1106 v.set_owner(name)
1107
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001108 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001109 if not self.tag_member: # flat union
Eric Blakeda9cb192016-07-13 21:50:15 -06001110 self.tag_member = seen[c_name(self._tag_name)]
1111 assert self._tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001112 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1113 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001114 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001115 # Union names must match enum values; alternate names are
1116 # checked separately. Use 'seen' to tell the two apart.
1117 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001118 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001119 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001120 v.type.check(schema)
1121
Eric Blake27b60ab2015-11-18 01:52:51 -07001122 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001123 for v in self.variants:
1124 # Reset seen map for each variant, since qapi names from one
1125 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001126 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001127 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001128
Eric Blake437db252015-09-29 16:21:02 -06001129
Markus Armbrusterac882192015-09-16 13:06:05 +02001130class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001131 role = 'branch'
1132
Markus Armbrusterac882192015-09-16 13:06:05 +02001133 def __init__(self, name, typ):
1134 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1135
Markus Armbrusterac882192015-09-16 13:06:05 +02001136
1137class QAPISchemaAlternateType(QAPISchemaType):
1138 def __init__(self, name, info, variants):
1139 QAPISchemaType.__init__(self, name, info)
1140 assert isinstance(variants, QAPISchemaObjectTypeVariants)
Eric Blakeda9cb192016-07-13 21:50:15 -06001141 assert variants.tag_member
Eric Blake88d4ef82015-11-18 01:52:50 -07001142 variants.set_owner(name)
1143 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001144 self.variants = variants
1145
1146 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001147 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001148 # Not calling self.variants.check_clash(), because there's nothing
1149 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001150 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001151 # Alternate branch names have no relation to the tag enum values;
1152 # so we have to check for potential name collisions ourselves.
1153 seen = {}
1154 for v in self.variants.variants:
1155 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001156
Eric Blake4040d992016-03-17 16:48:28 -06001157 def c_type(self):
1158 return c_name(self.name) + pointer_suffix
1159
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001160 def json_type(self):
1161 return 'value'
1162
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001163 def visit(self, visitor):
1164 visitor.visit_alternate_type(self.name, self.info, self.variants)
1165
Markus Armbrusterac882192015-09-16 13:06:05 +02001166
1167class QAPISchemaCommand(QAPISchemaEntity):
1168 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1169 QAPISchemaEntity.__init__(self, name, info)
1170 assert not arg_type or isinstance(arg_type, str)
1171 assert not ret_type or isinstance(ret_type, str)
1172 self._arg_type_name = arg_type
1173 self.arg_type = None
1174 self._ret_type_name = ret_type
1175 self.ret_type = None
1176 self.gen = gen
1177 self.success_response = success_response
1178
1179 def check(self, schema):
1180 if self._arg_type_name:
1181 self.arg_type = schema.lookup_type(self._arg_type_name)
1182 assert isinstance(self.arg_type, QAPISchemaObjectType)
1183 assert not self.arg_type.variants # not implemented
1184 if self._ret_type_name:
1185 self.ret_type = schema.lookup_type(self._ret_type_name)
1186 assert isinstance(self.ret_type, QAPISchemaType)
1187
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001188 def visit(self, visitor):
1189 visitor.visit_command(self.name, self.info,
1190 self.arg_type, self.ret_type,
1191 self.gen, self.success_response)
1192
Markus Armbrusterac882192015-09-16 13:06:05 +02001193
1194class QAPISchemaEvent(QAPISchemaEntity):
1195 def __init__(self, name, info, arg_type):
1196 QAPISchemaEntity.__init__(self, name, info)
1197 assert not arg_type or isinstance(arg_type, str)
1198 self._arg_type_name = arg_type
1199 self.arg_type = None
1200
1201 def check(self, schema):
1202 if self._arg_type_name:
1203 self.arg_type = schema.lookup_type(self._arg_type_name)
1204 assert isinstance(self.arg_type, QAPISchemaObjectType)
1205 assert not self.arg_type.variants # not implemented
1206
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001207 def visit(self, visitor):
1208 visitor.visit_event(self.name, self.info, self.arg_type)
1209
Markus Armbrusterac882192015-09-16 13:06:05 +02001210
1211class QAPISchema(object):
1212 def __init__(self, fname):
1213 try:
1214 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
Eric Blake7618b912015-10-12 22:22:22 -06001215 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001216 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001217 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001218 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001219 self._def_exprs()
1220 self.check()
Markus Armbruster291928a2015-12-18 08:52:41 +01001221 except (QAPISchemaError, QAPIExprError) as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001222 print >>sys.stderr, err
1223 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001224
Markus Armbrusterac882192015-09-16 13:06:05 +02001225 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001226 # Only the predefined types are allowed to not have info
1227 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001228 assert ent.name not in self._entity_dict
1229 self._entity_dict[ent.name] = ent
1230
1231 def lookup_entity(self, name, typ=None):
1232 ent = self._entity_dict.get(name)
1233 if typ and not isinstance(ent, typ):
1234 return None
1235 return ent
1236
1237 def lookup_type(self, name):
1238 return self.lookup_entity(name, QAPISchemaType)
1239
Eric Blake861877a2016-03-17 16:48:36 -06001240 def _def_builtin_type(self, name, json_type, c_type):
1241 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001242 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1243 # qapi-types.h from a single .c, all arrays of builtins must be
1244 # declared in the first file whether or not they are used. Nicer
1245 # would be to use lazy instantiation, while figuring out how to
1246 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001247 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001248
1249 def _def_predefineds(self):
Eric Blake861877a2016-03-17 16:48:36 -06001250 for t in [('str', 'string', 'char' + pointer_suffix),
1251 ('number', 'number', 'double'),
1252 ('int', 'int', 'int64_t'),
1253 ('int8', 'int', 'int8_t'),
1254 ('int16', 'int', 'int16_t'),
1255 ('int32', 'int', 'int32_t'),
1256 ('int64', 'int', 'int64_t'),
1257 ('uint8', 'int', 'uint8_t'),
1258 ('uint16', 'int', 'uint16_t'),
1259 ('uint32', 'int', 'uint32_t'),
1260 ('uint64', 'int', 'uint64_t'),
1261 ('size', 'int', 'uint64_t'),
1262 ('bool', 'boolean', 'bool'),
1263 ('any', 'value', 'QObject' + pointer_suffix)]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001264 self._def_builtin_type(*t)
Eric Blake75996972016-03-17 16:48:29 -06001265 self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1266 None, [], None)
Markus Armbruster39a18152015-09-16 13:06:28 +02001267 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001268 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1269 'qstring', 'qdict', 'qlist',
1270 'qfloat', 'qbool'])
1271 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001272 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001273
Eric Blake93bda4d2015-12-01 22:20:55 -07001274 def _make_enum_members(self, values):
1275 return [QAPISchemaMember(v) for v in values]
1276
Eric Blake99df5282015-10-12 22:22:32 -06001277 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001278 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001279 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001280 self._def_entity(QAPISchemaEnumType(
1281 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001282 return name
1283
Eric Blake99df5282015-10-12 22:22:32 -06001284 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001285 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001286 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001287 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001288 return name
1289
Eric Blake99df5282015-10-12 22:22:32 -06001290 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001291 if not members:
1292 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001293 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake75996972016-03-17 16:48:29 -06001294 name = 'q_obj_%s-%s' % (name, role)
Markus Armbrusterac882192015-09-16 13:06:05 +02001295 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001296 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001297 members, None))
1298 return name
1299
1300 def _def_enum_type(self, expr, info):
1301 name = expr['enum']
1302 data = expr['data']
1303 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001304 self._def_entity(QAPISchemaEnumType(
1305 name, info, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001306
Eric Blake99df5282015-10-12 22:22:32 -06001307 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001308 optional = False
1309 if name.startswith('*'):
1310 name = name[1:]
1311 optional = True
1312 if isinstance(typ, list):
1313 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001314 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001315 return QAPISchemaObjectTypeMember(name, typ, optional)
1316
Eric Blake99df5282015-10-12 22:22:32 -06001317 def _make_members(self, data, info):
1318 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001319 for (key, value) in data.iteritems()]
1320
1321 def _def_struct_type(self, expr, info):
1322 name = expr['struct']
1323 base = expr.get('base')
1324 data = expr['data']
1325 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001326 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001327 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001328
1329 def _make_variant(self, case, typ):
1330 return QAPISchemaObjectTypeVariant(case, typ)
1331
Eric Blake99df5282015-10-12 22:22:32 -06001332 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001333 if isinstance(typ, list):
1334 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001335 typ = self._make_array_type(typ[0], info)
1336 typ = self._make_implicit_object_type(
1337 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001338 return QAPISchemaObjectTypeVariant(case, typ)
1339
Markus Armbrusterac882192015-09-16 13:06:05 +02001340 def _def_union_type(self, expr, info):
1341 name = expr['union']
1342 data = expr['data']
1343 base = expr.get('base')
1344 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001345 tag_member = None
Eric Blakeac4338f2016-03-17 16:48:39 -06001346 if isinstance(base, dict):
1347 base = (self._make_implicit_object_type(
1348 name, info, 'base', self._make_members(base, info)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001349 if tag_name:
1350 variants = [self._make_variant(key, value)
1351 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001352 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001353 else:
Eric Blake99df5282015-10-12 22:22:32 -06001354 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001355 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001356 typ = self._make_implicit_enum_type(name, info,
1357 [v.name for v in variants])
1358 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001359 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001360 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001361 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001362 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001363 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001364 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001365
1366 def _def_alternate_type(self, expr, info):
1367 name = expr['alternate']
1368 data = expr['data']
1369 variants = [self._make_variant(key, value)
1370 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001371 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001372 self._def_entity(
1373 QAPISchemaAlternateType(name, info,
1374 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001375 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001376 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001377
1378 def _def_command(self, expr, info):
1379 name = expr['command']
1380 data = expr.get('data')
1381 rets = expr.get('returns')
1382 gen = expr.get('gen', True)
1383 success_response = expr.get('success-response', True)
1384 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001385 data = self._make_implicit_object_type(
1386 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001387 if isinstance(rets, list):
1388 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001389 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001390 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1391 success_response))
1392
1393 def _def_event(self, expr, info):
1394 name = expr['event']
1395 data = expr.get('data')
1396 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001397 data = self._make_implicit_object_type(
1398 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001399 self._def_entity(QAPISchemaEvent(name, info, data))
1400
1401 def _def_exprs(self):
1402 for expr_elem in self.exprs:
1403 expr = expr_elem['expr']
1404 info = expr_elem['info']
1405 if 'enum' in expr:
1406 self._def_enum_type(expr, info)
1407 elif 'struct' in expr:
1408 self._def_struct_type(expr, info)
1409 elif 'union' in expr:
1410 self._def_union_type(expr, info)
1411 elif 'alternate' in expr:
1412 self._def_alternate_type(expr, info)
1413 elif 'command' in expr:
1414 self._def_command(expr, info)
1415 elif 'event' in expr:
1416 self._def_event(expr, info)
1417 else:
1418 assert False
1419
1420 def check(self):
1421 for ent in self._entity_dict.values():
1422 ent.check(self)
1423
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001424 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001425 visitor.visit_begin(self)
1426 for (name, entity) in sorted(self._entity_dict.items()):
1427 if visitor.visit_needed(entity):
1428 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001429 visitor.visit_end()
1430
Markus Armbruster2caba362013-07-27 17:41:56 +02001431
Markus Armbruster00e4b282015-06-10 10:04:36 +02001432#
1433# Code generation helpers
1434#
1435
Michael Roth0f923be2011-07-19 14:50:39 -05001436def camel_case(name):
1437 new_name = ''
1438 first = True
1439 for ch in name:
1440 if ch in ['_', '-']:
1441 first = True
1442 elif first:
1443 new_name += ch.upper()
1444 first = False
1445 else:
1446 new_name += ch.lower()
1447 return new_name
1448
Eric Blake437db252015-09-29 16:21:02 -06001449
Markus Armbruster849bc532015-05-14 06:50:53 -06001450# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1451# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1452# ENUM24_Name -> ENUM24_NAME
1453def camel_to_upper(value):
1454 c_fun_str = c_name(value, False)
1455 if value.isupper():
1456 return c_fun_str
1457
1458 new_name = ''
1459 l = len(c_fun_str)
1460 for i in range(l):
1461 c = c_fun_str[i]
1462 # When c is upper and no "_" appears before, do more checks
1463 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001464 if i < l - 1 and c_fun_str[i + 1].islower():
1465 new_name += '_'
1466 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001467 new_name += '_'
1468 new_name += c
1469 return new_name.lstrip('_').upper()
1470
Eric Blake437db252015-09-29 16:21:02 -06001471
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001472def c_enum_const(type_name, const_name, prefix=None):
1473 if prefix is not None:
1474 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001475 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001476
Eric Blake18df5152015-05-14 06:50:48 -06001477c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001478
Eric Blake437db252015-09-29 16:21:02 -06001479
Eric Blakec6405b52015-05-14 06:50:55 -06001480# Map @name to a valid C identifier.
1481# If @protect, avoid returning certain ticklish identifiers (like
1482# C keywords) by prepending "q_".
1483#
1484# Used for converting 'name' from a 'name':'type' qapi definition
1485# into a generated struct member, as well as converting type names
1486# into substrings of a generated C function name.
1487# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1488# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001489def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001490 # ANSI X3J11/88-090, 3.1.1
1491 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001492 'default', 'do', 'double', 'else', 'enum', 'extern',
1493 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1494 'return', 'short', 'signed', 'sizeof', 'static',
1495 'struct', 'switch', 'typedef', 'union', 'unsigned',
1496 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001497 # ISO/IEC 9899:1999, 6.4.1
1498 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1499 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001500 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1501 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001502 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1503 # excluding _.*
1504 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001505 # C++ ISO/IEC 14882:2003 2.11
1506 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1507 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1508 'namespace', 'new', 'operator', 'private', 'protected',
1509 'public', 'reinterpret_cast', 'static_cast', 'template',
1510 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1511 'using', 'virtual', 'wchar_t',
1512 # alternative representations
1513 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1514 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001515 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001516 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001517 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001518 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1519 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001520 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001521 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001522
Amos Kong05dfb262014-06-10 19:25:53 +08001523eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001524pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001525
Eric Blake437db252015-09-29 16:21:02 -06001526
Michael Roth0f923be2011-07-19 14:50:39 -05001527def genindent(count):
1528 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001529 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001530 ret += " "
1531 return ret
1532
1533indent_level = 0
1534
Eric Blake437db252015-09-29 16:21:02 -06001535
Michael Roth0f923be2011-07-19 14:50:39 -05001536def push_indent(indent_amount=4):
1537 global indent_level
1538 indent_level += indent_amount
1539
Eric Blake437db252015-09-29 16:21:02 -06001540
Michael Roth0f923be2011-07-19 14:50:39 -05001541def pop_indent(indent_amount=4):
1542 global indent_level
1543 indent_level -= indent_amount
1544
Eric Blake437db252015-09-29 16:21:02 -06001545
Markus Armbruster77e703b2015-06-24 19:27:32 +02001546# Generate @code with @kwds interpolated.
1547# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001548def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001549 raw = code % kwds
1550 if indent_level:
1551 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001552 # re.subn() lacks flags support before Python 2.7, use re.compile()
1553 raw = re.subn(re.compile("^.", re.MULTILINE),
1554 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001555 raw = raw[0]
1556 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001557
Eric Blake437db252015-09-29 16:21:02 -06001558
Michael Roth0f923be2011-07-19 14:50:39 -05001559def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001560 if code[0] == '\n':
1561 code = code[1:]
1562 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001563
Michael Roth0f923be2011-07-19 14:50:39 -05001564
1565def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001566 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001567
Eric Blake437db252015-09-29 16:21:02 -06001568
Michael Rothc0afa9c2013-05-10 17:46:00 -05001569def guardstart(name):
1570 return mcgen('''
1571
1572#ifndef %(name)s
1573#define %(name)s
1574
1575''',
1576 name=guardname(name))
1577
Eric Blake437db252015-09-29 16:21:02 -06001578
Michael Rothc0afa9c2013-05-10 17:46:00 -05001579def guardend(name):
1580 return mcgen('''
1581
1582#endif /* %(name)s */
1583
1584''',
1585 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001586
Eric Blake437db252015-09-29 16:21:02 -06001587
Markus Armbrustere98859a2015-09-16 13:06:16 +02001588def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001589 ret = mcgen('''
1590
Markus Armbrustere98859a2015-09-16 13:06:16 +02001591const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001592''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001593 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001594 for value in values:
1595 index = c_enum_const(name, value, prefix)
1596 ret += mcgen('''
1597 [%(index)s] = "%(value)s",
1598''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001599 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001600
Eric Blake7fb1cf12015-11-18 01:52:57 -07001601 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001602 ret += mcgen('''
1603 [%(max_index)s] = NULL,
1604};
1605''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001606 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001607 return ret
1608
Eric Blake437db252015-09-29 16:21:02 -06001609
Markus Armbrustere98859a2015-09-16 13:06:16 +02001610def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001611 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001612 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001613
1614 ret = mcgen('''
1615
1616typedef enum %(c_name)s {
1617''',
1618 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001619
1620 i = 0
1621 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001622 ret += mcgen('''
1623 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001624''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001625 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001626 i=i)
1627 i += 1
1628
Markus Armbrustere98859a2015-09-16 13:06:16 +02001629 ret += mcgen('''
1630} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001631''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001632 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001633
Markus Armbrustere98859a2015-09-16 13:06:16 +02001634 ret += mcgen('''
1635
1636extern const char *const %(c_name)s_lookup[];
1637''',
1638 c_name=c_name(name))
1639 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001640
Eric Blake437db252015-09-29 16:21:02 -06001641
Markus Armbruster03b43672015-09-16 13:06:20 +02001642def gen_params(arg_type, extra):
1643 if not arg_type:
1644 return extra
1645 assert not arg_type.variants
1646 ret = ''
1647 sep = ''
1648 for memb in arg_type.members:
1649 ret += sep
1650 sep = ', '
1651 if memb.optional:
1652 ret += 'bool has_%s, ' % c_name(memb.name)
Eric Blake4040d992016-03-17 16:48:28 -06001653 ret += '%s %s' % (memb.type.c_param_type(), c_name(memb.name))
Markus Armbruster03b43672015-09-16 13:06:20 +02001654 if extra:
1655 ret += sep + extra
1656 return ret
1657
Eric Blake1f353342015-09-29 16:21:13 -06001658
Eric Blake12f254f2016-03-17 16:48:35 -06001659def gen_err_check():
Eric Blake1f353342015-09-29 16:21:13 -06001660 return mcgen('''
Eric Blake18bdbc32015-09-29 16:21:15 -06001661 if (err) {
Eric Blake12f254f2016-03-17 16:48:35 -06001662 goto out;
Eric Blake82ca8e42015-09-29 16:21:14 -06001663 }
1664''')
Eric Blake82ca8e42015-09-29 16:21:14 -06001665
1666
Markus Armbruster00e4b282015-06-10 10:04:36 +02001667#
1668# Common command line parsing
1669#
1670
Eric Blake437db252015-09-29 16:21:02 -06001671
1672def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001673
1674 try:
1675 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001676 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001677 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001678 "output-dir="] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001679 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001680 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001681 sys.exit(1)
1682
1683 output_dir = ""
1684 prefix = ""
1685 do_c = False
1686 do_h = False
1687 extra_opts = []
1688
1689 for oa in opts:
1690 o, a = oa
1691 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001692 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1693 if match.end() != len(a):
1694 print >>sys.stderr, \
1695 "%s: 'funny character '%s' in argument of --prefix" \
1696 % (sys.argv[0], a[match.end()])
1697 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001698 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001699 elif o in ("-o", "--output-dir"):
1700 output_dir = a + "/"
1701 elif o in ("-c", "--source"):
1702 do_c = True
1703 elif o in ("-h", "--header"):
1704 do_h = True
1705 else:
1706 extra_opts.append(oa)
1707
1708 if not do_c and not do_h:
1709 do_c = True
1710 do_h = True
1711
Markus Armbruster16d80f62015-04-02 13:32:16 +02001712 if len(args) != 1:
1713 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001714 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001715 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001716
Markus Armbruster54414042015-06-09 16:22:45 +02001717 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001718
Markus Armbruster00e4b282015-06-10 10:04:36 +02001719#
1720# Generate output files with boilerplate
1721#
1722
Eric Blake437db252015-09-29 16:21:02 -06001723
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001724def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1725 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001726 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001727 c_file = output_dir + prefix + c_file
1728 h_file = output_dir + prefix + h_file
1729
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001730 if output_dir:
1731 try:
1732 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01001733 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001734 if e.errno != errno.EEXIST:
1735 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001736
1737 def maybe_open(really, name, opt):
1738 if really:
1739 return open(name, opt)
1740 else:
1741 import StringIO
1742 return StringIO.StringIO()
1743
1744 fdef = maybe_open(do_c, c_file, 'w')
1745 fdecl = maybe_open(do_h, h_file, 'w')
1746
1747 fdef.write(mcgen('''
1748/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1749%(comment)s
1750''',
Eric Blake437db252015-09-29 16:21:02 -06001751 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001752
1753 fdecl.write(mcgen('''
1754/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1755%(comment)s
1756#ifndef %(guard)s
1757#define %(guard)s
1758
1759''',
Eric Blake437db252015-09-29 16:21:02 -06001760 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001761
1762 return (fdef, fdecl)
1763
Eric Blake437db252015-09-29 16:21:02 -06001764
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001765def close_output(fdef, fdecl):
1766 fdecl.write('''
1767#endif
1768''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001769 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001770 fdef.close()