blob: 400c4ef4a6df902318379620f87c6daec3701e7c [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):
Eric Blakecd50a252016-07-13 21:50:14 -06001003 assert self.name != 'q_empty'
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001004 return QAPISchemaType.c_name(self)
1005
Eric Blake4040d992016-03-17 16:48:28 -06001006 def c_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001007 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -07001008 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001009
Eric Blake4040d992016-03-17 16:48:28 -06001010 def c_unboxed_type(self):
Eric Blake4040d992016-03-17 16:48:28 -06001011 return c_name(self.name)
1012
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001013 def json_type(self):
1014 return 'object'
1015
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001016 def visit(self, visitor):
1017 visitor.visit_object_type(self.name, self.info,
1018 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001019 visitor.visit_object_type_flat(self.name, self.info,
1020 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001021
Markus Armbrusterac882192015-09-16 13:06:05 +02001022
Eric Blaked44f9ac2015-12-01 22:20:54 -07001023class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001024 role = 'member'
1025
Eric Blaked44f9ac2015-12-01 22:20:54 -07001026 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001027 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001028 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001029 self.owner = None
1030
1031 def set_owner(self, name):
1032 assert not self.owner
1033 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001034
Eric Blake27b60ab2015-11-18 01:52:51 -07001035 def check_clash(self, info, seen):
1036 cname = c_name(self.name)
Eric Blake893e1f22015-12-01 22:20:57 -07001037 if cname.lower() != cname and self.owner not in case_whitelist:
1038 raise QAPIExprError(info,
1039 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001040 if cname in seen:
1041 raise QAPIExprError(info,
1042 "%s collides with %s"
1043 % (self.describe(), seen[cname].describe()))
1044 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001045
Eric Blake88d4ef82015-11-18 01:52:50 -07001046 def _pretty_owner(self):
1047 owner = self.owner
Eric Blake75996972016-03-17 16:48:29 -06001048 if owner.startswith('q_obj_'):
Eric Blake88d4ef82015-11-18 01:52:50 -07001049 # See QAPISchema._make_implicit_object_type() - reverse the
1050 # mapping there to create a nice human-readable description
Eric Blake75996972016-03-17 16:48:29 -06001051 owner = owner[6:]
Eric Blake88d4ef82015-11-18 01:52:50 -07001052 if owner.endswith('-arg'):
1053 return '(parameter of %s)' % owner[:-4]
Eric Blakeac4338f2016-03-17 16:48:39 -06001054 elif owner.endswith('-base'):
1055 return '(base of %s)' % owner[:-5]
Eric Blake88d4ef82015-11-18 01:52:50 -07001056 else:
1057 assert owner.endswith('-wrapper')
1058 # Unreachable and not implemented
1059 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001060 if owner.endswith('Kind'):
1061 # See QAPISchema._make_implicit_enum_type()
1062 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001063 return '(%s of %s)' % (self.role, owner)
1064
1065 def describe(self):
1066 return "'%s' %s" % (self.name, self._pretty_owner())
1067
Markus Armbrusterac882192015-09-16 13:06:05 +02001068
Eric Blaked44f9ac2015-12-01 22:20:54 -07001069class QAPISchemaObjectTypeMember(QAPISchemaMember):
1070 def __init__(self, name, typ, optional):
1071 QAPISchemaMember.__init__(self, name)
1072 assert isinstance(typ, str)
1073 assert isinstance(optional, bool)
1074 self._type_name = typ
1075 self.type = None
1076 self.optional = optional
1077
1078 def check(self, schema):
1079 assert self.owner
1080 self.type = schema.lookup_type(self._type_name)
1081 assert self.type
1082
1083
Markus Armbrusterac882192015-09-16 13:06:05 +02001084class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001085 def __init__(self, tag_name, tag_member, variants):
1086 # Flat unions pass tag_name but not tag_member.
1087 # Simple unions and alternates pass tag_member but not tag_name.
1088 # After check(), tag_member is always set, and tag_name remains
1089 # a reliable witness of being used by a flat union.
1090 assert bool(tag_member) != bool(tag_name)
1091 assert (isinstance(tag_name, str) or
1092 isinstance(tag_member, QAPISchemaObjectTypeMember))
Eric Blake02a57ae2016-02-17 23:48:16 -07001093 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001094 for v in variants:
1095 assert isinstance(v, QAPISchemaObjectTypeVariant)
Eric Blakeda9cb192016-07-13 21:50:15 -06001096 self._tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001097 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001098 self.variants = variants
1099
Eric Blake88d4ef82015-11-18 01:52:50 -07001100 def set_owner(self, name):
1101 for v in self.variants:
1102 v.set_owner(name)
1103
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001104 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001105 if not self.tag_member: # flat union
Eric Blakeda9cb192016-07-13 21:50:15 -06001106 self.tag_member = seen[c_name(self._tag_name)]
1107 assert self._tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001108 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1109 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001110 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001111 # Union names must match enum values; alternate names are
1112 # checked separately. Use 'seen' to tell the two apart.
1113 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001114 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001115 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001116 v.type.check(schema)
1117
Eric Blake27b60ab2015-11-18 01:52:51 -07001118 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001119 for v in self.variants:
1120 # Reset seen map for each variant, since qapi names from one
1121 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001122 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001123 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001124
Eric Blake437db252015-09-29 16:21:02 -06001125
Markus Armbrusterac882192015-09-16 13:06:05 +02001126class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001127 role = 'branch'
1128
Markus Armbrusterac882192015-09-16 13:06:05 +02001129 def __init__(self, name, typ):
1130 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1131
Markus Armbrusterac882192015-09-16 13:06:05 +02001132
1133class QAPISchemaAlternateType(QAPISchemaType):
1134 def __init__(self, name, info, variants):
1135 QAPISchemaType.__init__(self, name, info)
1136 assert isinstance(variants, QAPISchemaObjectTypeVariants)
Eric Blakeda9cb192016-07-13 21:50:15 -06001137 assert variants.tag_member
Eric Blake88d4ef82015-11-18 01:52:50 -07001138 variants.set_owner(name)
1139 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001140 self.variants = variants
1141
1142 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001143 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001144 # Not calling self.variants.check_clash(), because there's nothing
1145 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001146 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001147 # Alternate branch names have no relation to the tag enum values;
1148 # so we have to check for potential name collisions ourselves.
1149 seen = {}
1150 for v in self.variants.variants:
1151 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001152
Eric Blake4040d992016-03-17 16:48:28 -06001153 def c_type(self):
1154 return c_name(self.name) + pointer_suffix
1155
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001156 def json_type(self):
1157 return 'value'
1158
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001159 def visit(self, visitor):
1160 visitor.visit_alternate_type(self.name, self.info, self.variants)
1161
Markus Armbrusterac882192015-09-16 13:06:05 +02001162
1163class QAPISchemaCommand(QAPISchemaEntity):
1164 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1165 QAPISchemaEntity.__init__(self, name, info)
1166 assert not arg_type or isinstance(arg_type, str)
1167 assert not ret_type or isinstance(ret_type, str)
1168 self._arg_type_name = arg_type
1169 self.arg_type = None
1170 self._ret_type_name = ret_type
1171 self.ret_type = None
1172 self.gen = gen
1173 self.success_response = success_response
1174
1175 def check(self, schema):
1176 if self._arg_type_name:
1177 self.arg_type = schema.lookup_type(self._arg_type_name)
1178 assert isinstance(self.arg_type, QAPISchemaObjectType)
1179 assert not self.arg_type.variants # not implemented
1180 if self._ret_type_name:
1181 self.ret_type = schema.lookup_type(self._ret_type_name)
1182 assert isinstance(self.ret_type, QAPISchemaType)
1183
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001184 def visit(self, visitor):
1185 visitor.visit_command(self.name, self.info,
1186 self.arg_type, self.ret_type,
1187 self.gen, self.success_response)
1188
Markus Armbrusterac882192015-09-16 13:06:05 +02001189
1190class QAPISchemaEvent(QAPISchemaEntity):
1191 def __init__(self, name, info, arg_type):
1192 QAPISchemaEntity.__init__(self, name, info)
1193 assert not arg_type or isinstance(arg_type, str)
1194 self._arg_type_name = arg_type
1195 self.arg_type = None
1196
1197 def check(self, schema):
1198 if self._arg_type_name:
1199 self.arg_type = schema.lookup_type(self._arg_type_name)
1200 assert isinstance(self.arg_type, QAPISchemaObjectType)
1201 assert not self.arg_type.variants # not implemented
1202
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001203 def visit(self, visitor):
1204 visitor.visit_event(self.name, self.info, self.arg_type)
1205
Markus Armbrusterac882192015-09-16 13:06:05 +02001206
1207class QAPISchema(object):
1208 def __init__(self, fname):
1209 try:
1210 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
Eric Blake7618b912015-10-12 22:22:22 -06001211 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001212 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001213 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001214 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001215 self._def_exprs()
1216 self.check()
Markus Armbruster291928a2015-12-18 08:52:41 +01001217 except (QAPISchemaError, QAPIExprError) as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001218 print >>sys.stderr, err
1219 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001220
Markus Armbrusterac882192015-09-16 13:06:05 +02001221 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001222 # Only the predefined types are allowed to not have info
1223 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001224 assert ent.name not in self._entity_dict
1225 self._entity_dict[ent.name] = ent
1226
1227 def lookup_entity(self, name, typ=None):
1228 ent = self._entity_dict.get(name)
1229 if typ and not isinstance(ent, typ):
1230 return None
1231 return ent
1232
1233 def lookup_type(self, name):
1234 return self.lookup_entity(name, QAPISchemaType)
1235
Eric Blake861877a2016-03-17 16:48:36 -06001236 def _def_builtin_type(self, name, json_type, c_type):
1237 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001238 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1239 # qapi-types.h from a single .c, all arrays of builtins must be
1240 # declared in the first file whether or not they are used. Nicer
1241 # would be to use lazy instantiation, while figuring out how to
1242 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001243 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001244
1245 def _def_predefineds(self):
Eric Blake861877a2016-03-17 16:48:36 -06001246 for t in [('str', 'string', 'char' + pointer_suffix),
1247 ('number', 'number', 'double'),
1248 ('int', 'int', 'int64_t'),
1249 ('int8', 'int', 'int8_t'),
1250 ('int16', 'int', 'int16_t'),
1251 ('int32', 'int', 'int32_t'),
1252 ('int64', 'int', 'int64_t'),
1253 ('uint8', 'int', 'uint8_t'),
1254 ('uint16', 'int', 'uint16_t'),
1255 ('uint32', 'int', 'uint32_t'),
1256 ('uint64', 'int', 'uint64_t'),
1257 ('size', 'int', 'uint64_t'),
1258 ('bool', 'boolean', 'bool'),
1259 ('any', 'value', 'QObject' + pointer_suffix)]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001260 self._def_builtin_type(*t)
Eric Blake75996972016-03-17 16:48:29 -06001261 self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1262 None, [], None)
Markus Armbruster39a18152015-09-16 13:06:28 +02001263 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001264 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1265 'qstring', 'qdict', 'qlist',
1266 'qfloat', 'qbool'])
1267 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001268 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001269
Eric Blake93bda4d2015-12-01 22:20:55 -07001270 def _make_enum_members(self, values):
1271 return [QAPISchemaMember(v) for v in values]
1272
Eric Blake99df5282015-10-12 22:22:32 -06001273 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001274 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001275 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001276 self._def_entity(QAPISchemaEnumType(
1277 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001278 return name
1279
Eric Blake99df5282015-10-12 22:22:32 -06001280 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001281 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001282 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001283 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001284 return name
1285
Eric Blake99df5282015-10-12 22:22:32 -06001286 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001287 if not members:
1288 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001289 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake75996972016-03-17 16:48:29 -06001290 name = 'q_obj_%s-%s' % (name, role)
Markus Armbrusterac882192015-09-16 13:06:05 +02001291 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001292 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001293 members, None))
1294 return name
1295
1296 def _def_enum_type(self, expr, info):
1297 name = expr['enum']
1298 data = expr['data']
1299 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001300 self._def_entity(QAPISchemaEnumType(
1301 name, info, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001302
Eric Blake99df5282015-10-12 22:22:32 -06001303 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001304 optional = False
1305 if name.startswith('*'):
1306 name = name[1:]
1307 optional = True
1308 if isinstance(typ, list):
1309 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001310 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001311 return QAPISchemaObjectTypeMember(name, typ, optional)
1312
Eric Blake99df5282015-10-12 22:22:32 -06001313 def _make_members(self, data, info):
1314 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001315 for (key, value) in data.iteritems()]
1316
1317 def _def_struct_type(self, expr, info):
1318 name = expr['struct']
1319 base = expr.get('base')
1320 data = expr['data']
1321 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001322 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001323 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001324
1325 def _make_variant(self, case, typ):
1326 return QAPISchemaObjectTypeVariant(case, typ)
1327
Eric Blake99df5282015-10-12 22:22:32 -06001328 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001329 if isinstance(typ, list):
1330 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001331 typ = self._make_array_type(typ[0], info)
1332 typ = self._make_implicit_object_type(
1333 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001334 return QAPISchemaObjectTypeVariant(case, typ)
1335
Markus Armbrusterac882192015-09-16 13:06:05 +02001336 def _def_union_type(self, expr, info):
1337 name = expr['union']
1338 data = expr['data']
1339 base = expr.get('base')
1340 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001341 tag_member = None
Eric Blakeac4338f2016-03-17 16:48:39 -06001342 if isinstance(base, dict):
1343 base = (self._make_implicit_object_type(
1344 name, info, 'base', self._make_members(base, info)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001345 if tag_name:
1346 variants = [self._make_variant(key, value)
1347 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001348 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001349 else:
Eric Blake99df5282015-10-12 22:22:32 -06001350 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001351 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001352 typ = self._make_implicit_enum_type(name, info,
1353 [v.name for v in variants])
1354 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001355 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001356 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001357 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001358 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001359 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001360 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001361
1362 def _def_alternate_type(self, expr, info):
1363 name = expr['alternate']
1364 data = expr['data']
1365 variants = [self._make_variant(key, value)
1366 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001367 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001368 self._def_entity(
1369 QAPISchemaAlternateType(name, info,
1370 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001371 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001372 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001373
1374 def _def_command(self, expr, info):
1375 name = expr['command']
1376 data = expr.get('data')
1377 rets = expr.get('returns')
1378 gen = expr.get('gen', True)
1379 success_response = expr.get('success-response', True)
1380 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001381 data = self._make_implicit_object_type(
1382 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001383 if isinstance(rets, list):
1384 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001385 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001386 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1387 success_response))
1388
1389 def _def_event(self, expr, info):
1390 name = expr['event']
1391 data = expr.get('data')
1392 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001393 data = self._make_implicit_object_type(
1394 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001395 self._def_entity(QAPISchemaEvent(name, info, data))
1396
1397 def _def_exprs(self):
1398 for expr_elem in self.exprs:
1399 expr = expr_elem['expr']
1400 info = expr_elem['info']
1401 if 'enum' in expr:
1402 self._def_enum_type(expr, info)
1403 elif 'struct' in expr:
1404 self._def_struct_type(expr, info)
1405 elif 'union' in expr:
1406 self._def_union_type(expr, info)
1407 elif 'alternate' in expr:
1408 self._def_alternate_type(expr, info)
1409 elif 'command' in expr:
1410 self._def_command(expr, info)
1411 elif 'event' in expr:
1412 self._def_event(expr, info)
1413 else:
1414 assert False
1415
1416 def check(self):
1417 for ent in self._entity_dict.values():
1418 ent.check(self)
1419
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001420 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001421 visitor.visit_begin(self)
1422 for (name, entity) in sorted(self._entity_dict.items()):
1423 if visitor.visit_needed(entity):
1424 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001425 visitor.visit_end()
1426
Markus Armbruster2caba362013-07-27 17:41:56 +02001427
Markus Armbruster00e4b282015-06-10 10:04:36 +02001428#
1429# Code generation helpers
1430#
1431
Michael Roth0f923be2011-07-19 14:50:39 -05001432def camel_case(name):
1433 new_name = ''
1434 first = True
1435 for ch in name:
1436 if ch in ['_', '-']:
1437 first = True
1438 elif first:
1439 new_name += ch.upper()
1440 first = False
1441 else:
1442 new_name += ch.lower()
1443 return new_name
1444
Eric Blake437db252015-09-29 16:21:02 -06001445
Markus Armbruster849bc532015-05-14 06:50:53 -06001446# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1447# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1448# ENUM24_Name -> ENUM24_NAME
1449def camel_to_upper(value):
1450 c_fun_str = c_name(value, False)
1451 if value.isupper():
1452 return c_fun_str
1453
1454 new_name = ''
1455 l = len(c_fun_str)
1456 for i in range(l):
1457 c = c_fun_str[i]
1458 # When c is upper and no "_" appears before, do more checks
1459 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001460 if i < l - 1 and c_fun_str[i + 1].islower():
1461 new_name += '_'
1462 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001463 new_name += '_'
1464 new_name += c
1465 return new_name.lstrip('_').upper()
1466
Eric Blake437db252015-09-29 16:21:02 -06001467
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001468def c_enum_const(type_name, const_name, prefix=None):
1469 if prefix is not None:
1470 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001471 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001472
Eric Blake18df5152015-05-14 06:50:48 -06001473c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001474
Eric Blake437db252015-09-29 16:21:02 -06001475
Eric Blakec6405b52015-05-14 06:50:55 -06001476# Map @name to a valid C identifier.
1477# If @protect, avoid returning certain ticklish identifiers (like
1478# C keywords) by prepending "q_".
1479#
1480# Used for converting 'name' from a 'name':'type' qapi definition
1481# into a generated struct member, as well as converting type names
1482# into substrings of a generated C function name.
1483# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1484# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001485def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001486 # ANSI X3J11/88-090, 3.1.1
1487 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001488 'default', 'do', 'double', 'else', 'enum', 'extern',
1489 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1490 'return', 'short', 'signed', 'sizeof', 'static',
1491 'struct', 'switch', 'typedef', 'union', 'unsigned',
1492 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001493 # ISO/IEC 9899:1999, 6.4.1
1494 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1495 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001496 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1497 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001498 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1499 # excluding _.*
1500 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001501 # C++ ISO/IEC 14882:2003 2.11
1502 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1503 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1504 'namespace', 'new', 'operator', 'private', 'protected',
1505 'public', 'reinterpret_cast', 'static_cast', 'template',
1506 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1507 'using', 'virtual', 'wchar_t',
1508 # alternative representations
1509 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1510 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001511 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001512 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001513 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001514 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1515 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001516 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001517 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001518
Amos Kong05dfb262014-06-10 19:25:53 +08001519eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001520pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001521
Eric Blake437db252015-09-29 16:21:02 -06001522
Michael Roth0f923be2011-07-19 14:50:39 -05001523def genindent(count):
1524 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001525 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001526 ret += " "
1527 return ret
1528
1529indent_level = 0
1530
Eric Blake437db252015-09-29 16:21:02 -06001531
Michael Roth0f923be2011-07-19 14:50:39 -05001532def push_indent(indent_amount=4):
1533 global indent_level
1534 indent_level += indent_amount
1535
Eric Blake437db252015-09-29 16:21:02 -06001536
Michael Roth0f923be2011-07-19 14:50:39 -05001537def pop_indent(indent_amount=4):
1538 global indent_level
1539 indent_level -= indent_amount
1540
Eric Blake437db252015-09-29 16:21:02 -06001541
Markus Armbruster77e703b2015-06-24 19:27:32 +02001542# Generate @code with @kwds interpolated.
1543# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001544def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001545 raw = code % kwds
1546 if indent_level:
1547 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001548 # re.subn() lacks flags support before Python 2.7, use re.compile()
1549 raw = re.subn(re.compile("^.", re.MULTILINE),
1550 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001551 raw = raw[0]
1552 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001553
Eric Blake437db252015-09-29 16:21:02 -06001554
Michael Roth0f923be2011-07-19 14:50:39 -05001555def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001556 if code[0] == '\n':
1557 code = code[1:]
1558 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001559
Michael Roth0f923be2011-07-19 14:50:39 -05001560
1561def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001562 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001563
Eric Blake437db252015-09-29 16:21:02 -06001564
Michael Rothc0afa9c2013-05-10 17:46:00 -05001565def guardstart(name):
1566 return mcgen('''
1567
1568#ifndef %(name)s
1569#define %(name)s
1570
1571''',
1572 name=guardname(name))
1573
Eric Blake437db252015-09-29 16:21:02 -06001574
Michael Rothc0afa9c2013-05-10 17:46:00 -05001575def guardend(name):
1576 return mcgen('''
1577
1578#endif /* %(name)s */
1579
1580''',
1581 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001582
Eric Blake437db252015-09-29 16:21:02 -06001583
Markus Armbrustere98859a2015-09-16 13:06:16 +02001584def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001585 ret = mcgen('''
1586
Markus Armbrustere98859a2015-09-16 13:06:16 +02001587const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001588''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001589 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001590 for value in values:
1591 index = c_enum_const(name, value, prefix)
1592 ret += mcgen('''
1593 [%(index)s] = "%(value)s",
1594''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001595 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001596
Eric Blake7fb1cf12015-11-18 01:52:57 -07001597 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001598 ret += mcgen('''
1599 [%(max_index)s] = NULL,
1600};
1601''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001602 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001603 return ret
1604
Eric Blake437db252015-09-29 16:21:02 -06001605
Markus Armbrustere98859a2015-09-16 13:06:16 +02001606def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001607 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001608 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001609
1610 ret = mcgen('''
1611
1612typedef enum %(c_name)s {
1613''',
1614 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001615
1616 i = 0
1617 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001618 ret += mcgen('''
1619 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001620''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001621 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001622 i=i)
1623 i += 1
1624
Markus Armbrustere98859a2015-09-16 13:06:16 +02001625 ret += mcgen('''
1626} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001627''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001628 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001629
Markus Armbrustere98859a2015-09-16 13:06:16 +02001630 ret += mcgen('''
1631
1632extern const char *const %(c_name)s_lookup[];
1633''',
1634 c_name=c_name(name))
1635 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001636
Eric Blake437db252015-09-29 16:21:02 -06001637
Markus Armbruster03b43672015-09-16 13:06:20 +02001638def gen_params(arg_type, extra):
1639 if not arg_type:
1640 return extra
1641 assert not arg_type.variants
1642 ret = ''
1643 sep = ''
1644 for memb in arg_type.members:
1645 ret += sep
1646 sep = ', '
1647 if memb.optional:
1648 ret += 'bool has_%s, ' % c_name(memb.name)
Eric Blake4040d992016-03-17 16:48:28 -06001649 ret += '%s %s' % (memb.type.c_param_type(), c_name(memb.name))
Markus Armbruster03b43672015-09-16 13:06:20 +02001650 if extra:
1651 ret += sep + extra
1652 return ret
1653
Eric Blake1f353342015-09-29 16:21:13 -06001654
Eric Blake12f254f2016-03-17 16:48:35 -06001655def gen_err_check():
Eric Blake1f353342015-09-29 16:21:13 -06001656 return mcgen('''
Eric Blake18bdbc32015-09-29 16:21:15 -06001657 if (err) {
Eric Blake12f254f2016-03-17 16:48:35 -06001658 goto out;
Eric Blake82ca8e42015-09-29 16:21:14 -06001659 }
1660''')
Eric Blake82ca8e42015-09-29 16:21:14 -06001661
1662
Markus Armbruster00e4b282015-06-10 10:04:36 +02001663#
1664# Common command line parsing
1665#
1666
Eric Blake437db252015-09-29 16:21:02 -06001667
1668def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001669
1670 try:
1671 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001672 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001673 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001674 "output-dir="] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001675 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001676 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001677 sys.exit(1)
1678
1679 output_dir = ""
1680 prefix = ""
1681 do_c = False
1682 do_h = False
1683 extra_opts = []
1684
1685 for oa in opts:
1686 o, a = oa
1687 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001688 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1689 if match.end() != len(a):
1690 print >>sys.stderr, \
1691 "%s: 'funny character '%s' in argument of --prefix" \
1692 % (sys.argv[0], a[match.end()])
1693 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001694 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001695 elif o in ("-o", "--output-dir"):
1696 output_dir = a + "/"
1697 elif o in ("-c", "--source"):
1698 do_c = True
1699 elif o in ("-h", "--header"):
1700 do_h = True
1701 else:
1702 extra_opts.append(oa)
1703
1704 if not do_c and not do_h:
1705 do_c = True
1706 do_h = True
1707
Markus Armbruster16d80f62015-04-02 13:32:16 +02001708 if len(args) != 1:
1709 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001710 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001711 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001712
Markus Armbruster54414042015-06-09 16:22:45 +02001713 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001714
Markus Armbruster00e4b282015-06-10 10:04:36 +02001715#
1716# Generate output files with boilerplate
1717#
1718
Eric Blake437db252015-09-29 16:21:02 -06001719
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001720def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1721 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001722 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001723 c_file = output_dir + prefix + c_file
1724 h_file = output_dir + prefix + h_file
1725
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001726 if output_dir:
1727 try:
1728 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01001729 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001730 if e.errno != errno.EEXIST:
1731 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001732
1733 def maybe_open(really, name, opt):
1734 if really:
1735 return open(name, opt)
1736 else:
1737 import StringIO
1738 return StringIO.StringIO()
1739
1740 fdef = maybe_open(do_c, c_file, 'w')
1741 fdecl = maybe_open(do_h, h_file, 'w')
1742
1743 fdef.write(mcgen('''
1744/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1745%(comment)s
1746''',
Eric Blake437db252015-09-29 16:21:02 -06001747 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001748
1749 fdecl.write(mcgen('''
1750/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1751%(comment)s
1752#ifndef %(guard)s
1753#define %(guard)s
1754
1755''',
Eric Blake437db252015-09-29 16:21:02 -06001756 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001757
1758 return (fdef, fdecl)
1759
Eric Blake437db252015-09-29 16:21:02 -06001760
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001761def close_output(fdef, fdecl):
1762 fdecl.write('''
1763#endif
1764''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001765 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001766 fdef.close()