blob: a38ef52922a4a49afa604c50a01eaaf06bfda0e9 [file] [log] [blame]
Michael Roth0f923be2011-07-19 14:50:39 -05001#
2# QAPI helper library
3#
4# Copyright IBM, Corp. 2011
Eric Blakee4083112016-01-29 06:48:41 -07005# Copyright (c) 2013-2016 Red Hat Inc.
Michael Roth0f923be2011-07-19 14:50:39 -05006#
7# Authors:
8# Anthony Liguori <aliguori@us.ibm.com>
Markus Armbrusterc7a3f252013-07-27 17:41:55 +02009# Markus Armbruster <armbru@redhat.com>
Michael Roth0f923be2011-07-19 14:50:39 -050010#
Markus Armbruster678e48a2014-03-01 08:40:34 +010011# This work is licensed under the terms of the GNU GPL, version 2.
12# See the COPYING file in the top-level directory.
Michael Roth0f923be2011-07-19 14:50:39 -050013
Lluís Vilanovaa719a272014-05-07 20:46:15 +020014import re
Michael Roth0f923be2011-07-19 14:50:39 -050015from ordereddict import OrderedDict
Markus Armbruster12f8e1b2015-04-02 14:46:39 +020016import errno
Markus Armbruster2114f5a2015-04-02 13:12:21 +020017import getopt
Lluís Vilanova33aaad52014-05-02 15:52:35 +020018import os
Markus Armbruster2caba362013-07-27 17:41:56 +020019import sys
Markus Armbruster47299262015-05-14 06:50:47 -060020import string
Michael Roth0f923be2011-07-19 14:50:39 -050021
Eric Blakeb52c4b92015-05-04 09:05:00 -060022builtin_types = {
Kevin Wolf69dd62d2013-07-08 16:14:21 +020023 'str': 'QTYPE_QSTRING',
24 'int': 'QTYPE_QINT',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
27 'int8': 'QTYPE_QINT',
28 'int16': 'QTYPE_QINT',
29 'int32': 'QTYPE_QINT',
30 'int64': 'QTYPE_QINT',
31 'uint8': 'QTYPE_QINT',
32 'uint16': 'QTYPE_QINT',
33 'uint32': 'QTYPE_QINT',
34 'uint64': 'QTYPE_QINT',
Eric Blakecb17f792015-05-04 09:05:01 -060035 'size': 'QTYPE_QINT',
Eric Blake1310a3d2015-12-01 22:20:46 -070036 'any': None, # any QType possible, actually
Eric Blake7264f5c2015-12-01 22:20:47 -070037 'QType': 'QTYPE_QSTRING',
Kevin Wolf69dd62d2013-07-08 16:14:21 +020038}
39
Eric Blake10d4d992015-05-04 09:05:23 -060040# Whitelist of commands allowed to return a non-dictionary
41returns_whitelist = [
42 # From QMP:
43 'human-monitor-command',
Markus Armbruster6eb39372015-09-16 13:06:25 +020044 'qom-get',
Eric Blake10d4d992015-05-04 09:05:23 -060045 'query-migrate-cache-size',
46 'query-tpm-models',
47 'query-tpm-types',
48 'ringbuf-read',
49
50 # From QGA:
51 'guest-file-open',
52 'guest-fsfreeze-freeze',
53 'guest-fsfreeze-freeze-list',
54 'guest-fsfreeze-status',
55 'guest-fsfreeze-thaw',
56 'guest-get-time',
57 'guest-set-vcpus',
58 'guest-sync',
59 'guest-sync-delimited',
Eric Blake10d4d992015-05-04 09:05:23 -060060]
61
Eric Blake893e1f22015-12-01 22:20:57 -070062# Whitelist of entities allowed to violate case conventions
63case_whitelist = [
64 # From QMP:
65 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
66 'CpuInfoBase', # CPU, visible through query-cpu
67 'CpuInfoMIPS', # PC, visible through query-cpu
68 'CpuInfoTricore', # PC, visible through query-cpu
Eric Blake893e1f22015-12-01 22:20:57 -070069 'QapiErrorClass', # all members, visible through errors
70 'UuidInfo', # UUID, visible through query-uuid
71 'X86CPURegister32', # all members, visible indirectly through qom-get
72]
73
Eric Blake4dc2e692015-05-04 09:05:17 -060074enum_types = []
75struct_types = []
76union_types = []
77events = []
78all_names = {}
79
Markus Armbruster00e4b282015-06-10 10:04:36 +020080#
81# Parsing the schema into expressions
82#
83
Eric Blake437db252015-09-29 16:21:02 -060084
Lluís Vilanovaa719a272014-05-07 20:46:15 +020085def error_path(parent):
86 res = ""
87 while parent:
88 res = ("In file included from %s:%d:\n" % (parent['file'],
89 parent['line'])) + res
90 parent = parent['parent']
91 return res
92
Eric Blake437db252015-09-29 16:21:02 -060093
Markus Armbruster2caba362013-07-27 17:41:56 +020094class QAPISchemaError(Exception):
95 def __init__(self, schema, msg):
Eric Blake59b00542015-09-29 16:21:01 -060096 Exception.__init__(self)
Markus Armbruster54414042015-06-09 16:22:45 +020097 self.fname = schema.fname
Markus Armbruster2caba362013-07-27 17:41:56 +020098 self.msg = msg
Wenchao Xia515b9432014-03-04 18:44:33 -080099 self.col = 1
100 self.line = schema.line
101 for ch in schema.src[schema.line_pos:schema.pos]:
102 if ch == '\t':
Markus Armbruster2caba362013-07-27 17:41:56 +0200103 self.col = (self.col + 7) % 8 + 1
104 else:
105 self.col += 1
Markus Armbruster54414042015-06-09 16:22:45 +0200106 self.info = schema.incl_info
Markus Armbruster2caba362013-07-27 17:41:56 +0200107
108 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200109 return error_path(self.info) + \
Markus Armbruster54414042015-06-09 16:22:45 +0200110 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
Markus Armbruster2caba362013-07-27 17:41:56 +0200111
Eric Blake437db252015-09-29 16:21:02 -0600112
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800113class QAPIExprError(Exception):
114 def __init__(self, expr_info, msg):
Eric Blake59b00542015-09-29 16:21:01 -0600115 Exception.__init__(self)
Eric Blake7618b912015-10-12 22:22:22 -0600116 assert expr_info
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200117 self.info = expr_info
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800118 self.msg = msg
119
120 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200121 return error_path(self.info['parent']) + \
122 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800123
Eric Blake437db252015-09-29 16:21:02 -0600124
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200125class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500126
Eric Blake437db252015-09-29 16:21:02 -0600127 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200128 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200129 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200130 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200131 previously_included.append(abs_fname)
132 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200133 self.src = fp.read()
134 if self.src == '' or self.src[-1] != '\n':
135 self.src += '\n'
136 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800137 self.line = 1
138 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200139 self.exprs = []
140 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500141
Eric Blake437db252015-09-29 16:21:02 -0600142 while self.tok is not None:
Markus Armbruster54414042015-06-09 16:22:45 +0200143 expr_info = {'file': fname, 'line': self.line,
144 'parent': self.incl_info}
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200145 expr = self.get_expr(False)
146 if isinstance(expr, dict) and "include" in expr:
147 if len(expr) != 1:
Eric Blake437db252015-09-29 16:21:02 -0600148 raise QAPIExprError(expr_info,
149 "Invalid 'include' directive")
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200150 include = expr["include"]
151 if not isinstance(include, str):
152 raise QAPIExprError(expr_info,
Eric Blake7408fb62015-09-29 16:21:00 -0600153 "Value of 'include' must be a string")
Markus Armbruster54414042015-06-09 16:22:45 +0200154 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
155 include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200156 # catch inclusion cycle
157 inf = expr_info
158 while inf:
159 if incl_abs_fname == os.path.abspath(inf['file']):
Stefan Hajnoczi7ac9a9d2014-08-27 12:08:51 +0100160 raise QAPIExprError(expr_info, "Inclusion loop for %s"
161 % include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200162 inf = inf['parent']
Benoît Canet24fd8482014-05-16 12:51:56 +0200163 # skip multiple include of the same file
Markus Armbruster54414042015-06-09 16:22:45 +0200164 if incl_abs_fname in previously_included:
Benoît Canet24fd8482014-05-16 12:51:56 +0200165 continue
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200166 try:
Markus Armbruster54414042015-06-09 16:22:45 +0200167 fobj = open(incl_abs_fname, 'r')
Markus Armbruster291928a2015-12-18 08:52:41 +0100168 except IOError as e:
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200169 raise QAPIExprError(expr_info,
170 '%s: %s' % (e.strerror, include))
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200171 exprs_include = QAPISchemaParser(fobj, previously_included,
172 expr_info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200173 self.exprs.extend(exprs_include.exprs)
174 else:
175 expr_elem = {'expr': expr,
176 'info': expr_info}
177 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500178
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200179 def accept(self):
180 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200181 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200182 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200183 self.cursor += 1
184 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500185
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200186 if self.tok == '#':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200187 self.cursor = self.src.find('\n', self.cursor)
Eric Blake8712fa52015-10-26 16:34:41 -0600188 elif self.tok in "{}:,[]":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200189 return
190 elif self.tok == "'":
191 string = ''
192 esc = False
193 while True:
194 ch = self.src[self.cursor]
195 self.cursor += 1
196 if ch == '\n':
Markus Armbruster2caba362013-07-27 17:41:56 +0200197 raise QAPISchemaError(self,
198 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200199 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600200 if ch == 'b':
201 string += '\b'
202 elif ch == 'f':
203 string += '\f'
204 elif ch == 'n':
205 string += '\n'
206 elif ch == 'r':
207 string += '\r'
208 elif ch == 't':
209 string += '\t'
210 elif ch == 'u':
211 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600212 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600213 ch = self.src[self.cursor]
214 self.cursor += 1
215 if ch not in "0123456789abcdefABCDEF":
216 raise QAPISchemaError(self,
217 '\\u escape needs 4 '
218 'hex digits')
219 value = (value << 4) + int(ch, 16)
220 # If Python 2 and 3 didn't disagree so much on
221 # how to handle Unicode, then we could allow
222 # Unicode string defaults. But most of QAPI is
223 # ASCII-only, so we aren't losing much for now.
224 if not value or value > 0x7f:
225 raise QAPISchemaError(self,
226 'For now, \\u escape '
227 'only supports non-zero '
228 'values up to \\u007f')
229 string += chr(value)
230 elif ch in "\\/'\"":
231 string += ch
232 else:
233 raise QAPISchemaError(self,
Eric Blake437db252015-09-29 16:21:02 -0600234 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200235 esc = False
236 elif ch == "\\":
237 esc = True
238 elif ch == "'":
239 self.val = string
240 return
241 else:
242 string += ch
Markus Armbrustere565d932015-06-10 08:24:58 +0200243 elif self.src.startswith("true", self.pos):
244 self.val = True
245 self.cursor += 3
246 return
247 elif self.src.startswith("false", self.pos):
248 self.val = False
249 self.cursor += 4
250 return
251 elif self.src.startswith("null", self.pos):
252 self.val = None
253 self.cursor += 3
254 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200255 elif self.tok == '\n':
256 if self.cursor == len(self.src):
257 self.tok = None
258 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800259 self.line += 1
260 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200261 elif not self.tok.isspace():
262 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500263
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200264 def get_members(self):
265 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200266 if self.tok == '}':
267 self.accept()
268 return expr
269 if self.tok != "'":
270 raise QAPISchemaError(self, 'Expected string or "}"')
271 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200272 key = self.val
273 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200274 if self.tok != ':':
275 raise QAPISchemaError(self, 'Expected ":"')
276 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800277 if key in expr:
278 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200279 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200280 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200281 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200282 return expr
283 if self.tok != ',':
284 raise QAPISchemaError(self, 'Expected "," or "}"')
285 self.accept()
286 if self.tok != "'":
287 raise QAPISchemaError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500288
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200289 def get_values(self):
290 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200291 if self.tok == ']':
292 self.accept()
293 return expr
Eric Blake437db252015-09-29 16:21:02 -0600294 if self.tok not in "{['tfn":
Fam Zhenge53188a2015-05-04 09:05:18 -0600295 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
296 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200297 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200298 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200299 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200300 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200301 return expr
302 if self.tok != ',':
303 raise QAPISchemaError(self, 'Expected "," or "]"')
304 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500305
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200306 def get_expr(self, nested):
307 if self.tok != '{' and not nested:
308 raise QAPISchemaError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200309 if self.tok == '{':
310 self.accept()
311 expr = self.get_members()
312 elif self.tok == '[':
313 self.accept()
314 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600315 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200316 expr = self.val
317 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200318 else:
319 raise QAPISchemaError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200320 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200321
Markus Armbruster00e4b282015-06-10 10:04:36 +0200322#
323# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200324# TODO fold into QAPISchema
325# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200326#
327
Eric Blake437db252015-09-29 16:21:02 -0600328
Eric Blake14f00c62016-03-03 09:16:43 -0700329def find_base_members(base):
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 Blake437db252015-09-29 16:21:02 -0600615
Eric Blake811d04f2015-05-04 09:05:10 -0600616def check_alternate(expr, expr_info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600617 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600618 members = expr['data']
Eric Blake811d04f2015-05-04 09:05:10 -0600619 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600620
Eric Blake02a57ae2016-02-17 23:48:16 -0700621 # Check every branch; require at least two branches
622 if len(members) < 2:
623 raise QAPIExprError(expr_info,
624 "Alternate '%s' should have at least two branches "
625 "in 'data'" % name)
Eric Blake811d04f2015-05-04 09:05:10 -0600626 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600627 check_name(expr_info, "Member of alternate '%s'" % name, key)
628
Eric Blake811d04f2015-05-04 09:05:10 -0600629 # Ensure alternates have no type conflicts.
Eric Blakedd883c62015-05-04 09:05:21 -0600630 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
631 value,
632 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600633 qtype = find_alternate_member_qtype(value)
Eric Blake46534302016-02-17 23:48:17 -0700634 if not qtype:
635 raise QAPIExprError(expr_info,
636 "Alternate '%s' member '%s' cannot use "
637 "type '%s'" % (name, key, value))
Eric Blake811d04f2015-05-04 09:05:10 -0600638 if qtype in types_seen:
639 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600640 "Alternate '%s' member '%s' can't "
Eric Blake811d04f2015-05-04 09:05:10 -0600641 "be distinguished from member '%s'"
642 % (name, key, types_seen[qtype]))
643 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800644
Eric Blake437db252015-09-29 16:21:02 -0600645
Eric Blakecf393592015-05-04 09:05:04 -0600646def check_enum(expr, expr_info):
647 name = expr['enum']
648 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100649 prefix = expr.get('prefix')
Eric Blakecf393592015-05-04 09:05:04 -0600650
651 if not isinstance(members, list):
652 raise QAPIExprError(expr_info,
653 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100654 if prefix is not None and not isinstance(prefix, str):
655 raise QAPIExprError(expr_info,
656 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600657 for member in members:
Eric Blake437db252015-09-29 16:21:02 -0600658 check_name(expr_info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600659 enum_member=True)
Eric Blakecf393592015-05-04 09:05:04 -0600660
Eric Blake437db252015-09-29 16:21:02 -0600661
Eric Blakedd883c62015-05-04 09:05:21 -0600662def check_struct(expr, expr_info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600663 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600664 members = expr['data']
665
Eric Blakefd41dd42015-05-04 09:05:25 -0600666 check_type(expr_info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600667 allow_dict=True, allow_optional=True)
Eric Blakefd41dd42015-05-04 09:05:25 -0600668 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600669 allow_metas=['struct'])
670
Eric Blake437db252015-09-29 16:21:02 -0600671
Eric Blake0545f6b2015-05-04 09:05:15 -0600672def check_keys(expr_elem, meta, required, optional=[]):
673 expr = expr_elem['expr']
674 info = expr_elem['info']
675 name = expr[meta]
676 if not isinstance(name, str):
677 raise QAPIExprError(info,
678 "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600679 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600680 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600681 if key not in required and key not in optional:
Eric Blake0545f6b2015-05-04 09:05:15 -0600682 raise QAPIExprError(info,
683 "Unknown key '%s' in %s '%s'"
684 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600685 if (key == 'gen' or key == 'success-response') and value is not False:
Eric Blake2cbf0992015-05-04 09:05:24 -0600686 raise QAPIExprError(info,
687 "'%s' of %s '%s' should only use false value"
688 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600689 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600690 if key not in expr:
Eric Blake0545f6b2015-05-04 09:05:15 -0600691 raise QAPIExprError(info,
692 "Key '%s' is missing from %s '%s'"
693 % (key, meta, name))
694
Eric Blake437db252015-09-29 16:21:02 -0600695
Markus Armbruster4d076d62015-06-10 08:55:21 +0200696def check_exprs(exprs):
697 global all_names
698
699 # Learn the types and check for valid expression keys
700 for builtin in builtin_types.keys():
701 all_names[builtin] = 'built-in'
702 for expr_elem in exprs:
703 expr = expr_elem['expr']
704 info = expr_elem['info']
Eric Blake437db252015-09-29 16:21:02 -0600705 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100706 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200707 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600708 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200709 check_keys(expr_elem, 'union', ['data'],
710 ['base', 'discriminator'])
711 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600712 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200713 check_keys(expr_elem, 'alternate', ['data'])
714 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600715 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200716 check_keys(expr_elem, 'struct', ['data'], ['base'])
717 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600718 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200719 check_keys(expr_elem, 'command', [],
720 ['data', 'returns', 'gen', 'success-response'])
721 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600722 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200723 check_keys(expr_elem, 'event', [], ['data'])
724 add_name(expr['event'], info, 'event')
725 else:
726 raise QAPIExprError(expr_elem['info'],
727 "Expression is missing metatype")
728
729 # Try again for hidden UnionKind enum
730 for expr_elem in exprs:
731 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600732 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200733 if not discriminator_find_enum_define(expr):
734 add_enum('%sKind' % expr['union'], expr_elem['info'],
735 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600736 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200737 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
738 implicit=True)
739
740 # Validate that exprs make sense
741 for expr_elem in exprs:
742 expr = expr_elem['expr']
743 info = expr_elem['info']
744
Eric Blake437db252015-09-29 16:21:02 -0600745 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200746 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600747 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200748 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600749 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200750 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600751 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200752 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600753 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200754 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600755 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200756 check_event(expr, info)
757 else:
758 assert False, 'unexpected meta type'
759
Markus Armbrusterac882192015-09-16 13:06:05 +0200760 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600761
Markus Armbrusterac882192015-09-16 13:06:05 +0200762
763#
764# Schema compiler frontend
765#
766
767class QAPISchemaEntity(object):
768 def __init__(self, name, info):
769 assert isinstance(name, str)
770 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -0600771 # For explicitly defined entities, info points to the (explicit)
772 # definition. For builtins (and their arrays), info is None.
773 # For implicitly defined entities, info points to a place that
774 # triggered the implicit definition (there may be more than one
775 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +0200776 self.info = info
777
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200778 def c_name(self):
779 return c_name(self.name)
780
Markus Armbrusterac882192015-09-16 13:06:05 +0200781 def check(self, schema):
782 pass
783
Eric Blake49823c42015-10-12 22:22:27 -0600784 def is_implicit(self):
785 return not self.info
786
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200787 def visit(self, visitor):
788 pass
789
790
791class QAPISchemaVisitor(object):
792 def visit_begin(self, schema):
793 pass
794
795 def visit_end(self):
796 pass
797
Eric Blake25a0d9c2015-10-12 22:22:21 -0600798 def visit_needed(self, entity):
799 # Default to visiting everything
800 return True
801
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200802 def visit_builtin_type(self, name, info, json_type):
803 pass
804
805 def visit_enum_type(self, name, info, values, prefix):
806 pass
807
808 def visit_array_type(self, name, info, element_type):
809 pass
810
811 def visit_object_type(self, name, info, base, members, variants):
812 pass
813
Markus Armbruster39a18152015-09-16 13:06:28 +0200814 def visit_object_type_flat(self, name, info, members, variants):
815 pass
816
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200817 def visit_alternate_type(self, name, info, variants):
818 pass
819
820 def visit_command(self, name, info, arg_type, ret_type,
821 gen, success_response):
822 pass
823
824 def visit_event(self, name, info, arg_type):
825 pass
826
Markus Armbrusterac882192015-09-16 13:06:05 +0200827
828class QAPISchemaType(QAPISchemaEntity):
Eric Blake4040d992016-03-17 16:48:28 -0600829 # Return the C type for common use.
830 # For the types we commonly box, this is a pointer type.
831 def c_type(self):
832 pass
833
834 # Return the C type to be used in a parameter list.
835 def c_param_type(self):
836 return self.c_type()
837
838 # Return the C type to be used where we suppress boxing.
839 def c_unboxed_type(self):
840 return self.c_type()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200841
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200842 def json_type(self):
843 pass
844
845 def alternate_qtype(self):
846 json2qtype = {
847 'string': 'QTYPE_QSTRING',
848 'number': 'QTYPE_QFLOAT',
849 'int': 'QTYPE_QINT',
850 'boolean': 'QTYPE_QBOOL',
851 'object': 'QTYPE_QDICT'
852 }
853 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +0200854
855
856class QAPISchemaBuiltinType(QAPISchemaType):
Eric Blake861877a2016-03-17 16:48:36 -0600857 def __init__(self, name, json_type, c_type):
Markus Armbrusterac882192015-09-16 13:06:05 +0200858 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200859 assert not c_type or isinstance(c_type, str)
860 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
861 'value')
862 self._json_type_name = json_type
863 self._c_type_name = c_type
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200864
865 def c_name(self):
866 return self.name
867
Eric Blake4040d992016-03-17 16:48:28 -0600868 def c_type(self):
869 return self._c_type_name
870
871 def c_param_type(self):
872 if self.name == 'str':
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200873 return 'const ' + self._c_type_name
874 return self._c_type_name
875
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200876 def json_type(self):
877 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +0200878
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200879 def visit(self, visitor):
880 visitor.visit_builtin_type(self.name, self.info, self.json_type())
881
Markus Armbrusterac882192015-09-16 13:06:05 +0200882
883class QAPISchemaEnumType(QAPISchemaType):
884 def __init__(self, name, info, values, prefix):
885 QAPISchemaType.__init__(self, name, info)
886 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -0700887 assert isinstance(v, QAPISchemaMember)
888 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200889 assert prefix is None or isinstance(prefix, str)
890 self.values = values
891 self.prefix = prefix
892
893 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -0700894 seen = {}
895 for v in self.values:
896 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200897
Eric Blake99df5282015-10-12 22:22:32 -0600898 def is_implicit(self):
899 # See QAPISchema._make_implicit_enum_type()
Eric Blake8712fa52015-10-26 16:34:41 -0600900 return self.name.endswith('Kind')
Eric Blake99df5282015-10-12 22:22:32 -0600901
Eric Blake4040d992016-03-17 16:48:28 -0600902 def c_type(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200903 return c_name(self.name)
904
Eric Blake93bda4d2015-12-01 22:20:55 -0700905 def member_names(self):
906 return [v.name for v in self.values]
907
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200908 def json_type(self):
909 return 'string'
910
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200911 def visit(self, visitor):
912 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -0700913 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200914
Markus Armbrusterac882192015-09-16 13:06:05 +0200915
916class QAPISchemaArrayType(QAPISchemaType):
917 def __init__(self, name, info, element_type):
918 QAPISchemaType.__init__(self, name, info)
919 assert isinstance(element_type, str)
920 self._element_type_name = element_type
921 self.element_type = None
922
923 def check(self, schema):
924 self.element_type = schema.lookup_type(self._element_type_name)
925 assert self.element_type
926
Eric Blake99df5282015-10-12 22:22:32 -0600927 def is_implicit(self):
928 return True
929
Eric Blake4040d992016-03-17 16:48:28 -0600930 def c_type(self):
931 return c_name(self.name) + pointer_suffix
932
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200933 def json_type(self):
934 return 'array'
935
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200936 def visit(self, visitor):
937 visitor.visit_array_type(self.name, self.info, self.element_type)
938
Markus Armbrusterac882192015-09-16 13:06:05 +0200939
940class QAPISchemaObjectType(QAPISchemaType):
941 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -0700942 # struct has local_members, optional base, and no variants
943 # flat union has base, variants, and no local_members
944 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +0200945 QAPISchemaType.__init__(self, name, info)
946 assert base is None or isinstance(base, str)
947 for m in local_members:
948 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -0700949 m.set_owner(name)
950 if variants is not None:
951 assert isinstance(variants, QAPISchemaObjectTypeVariants)
952 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200953 self._base_name = base
954 self.base = None
955 self.local_members = local_members
956 self.variants = variants
957 self.members = None
958
959 def check(self, schema):
Eric Blakebac54292015-12-01 22:20:59 -0700960 if self.members is False: # check for cycles
961 raise QAPIExprError(self.info,
962 "Object %s contains itself" % self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200963 if self.members:
964 return
965 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -0700966 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +0200967 if self._base_name:
968 self.base = schema.lookup_type(self._base_name)
969 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +0200970 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700971 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200972 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -0700973 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700974 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700975 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +0200976 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -0700977 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700978 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -0700979 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200980
Eric Blake14f00c62016-03-03 09:16:43 -0700981 # Check that the members of this type do not cause duplicate JSON members,
Eric Blake27b60ab2015-11-18 01:52:51 -0700982 # and update seen to track the members seen so far. Report any errors
983 # on behalf of info, which is not necessarily self.info
984 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -0700985 assert not self.variants # not implemented
986 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -0700987 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -0700988
Eric Blake99df5282015-10-12 22:22:32 -0600989 def is_implicit(self):
Eric Blake75996972016-03-17 16:48:29 -0600990 # See QAPISchema._make_implicit_object_type(), as well as
991 # _def_predefineds()
992 return self.name.startswith('q_')
Eric Blake99df5282015-10-12 22:22:32 -0600993
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200994 def c_name(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200995 return QAPISchemaType.c_name(self)
996
Eric Blake4040d992016-03-17 16:48:28 -0600997 def c_type(self):
Eric Blake49823c42015-10-12 22:22:27 -0600998 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -0700999 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001000
Eric Blake4040d992016-03-17 16:48:28 -06001001 def c_unboxed_type(self):
Eric Blake4040d992016-03-17 16:48:28 -06001002 return c_name(self.name)
1003
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001004 def json_type(self):
1005 return 'object'
1006
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001007 def visit(self, visitor):
1008 visitor.visit_object_type(self.name, self.info,
1009 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001010 visitor.visit_object_type_flat(self.name, self.info,
1011 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001012
Markus Armbrusterac882192015-09-16 13:06:05 +02001013
Eric Blaked44f9ac2015-12-01 22:20:54 -07001014class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001015 role = 'member'
1016
Eric Blaked44f9ac2015-12-01 22:20:54 -07001017 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001018 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001019 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001020 self.owner = None
1021
1022 def set_owner(self, name):
1023 assert not self.owner
1024 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001025
Eric Blake27b60ab2015-11-18 01:52:51 -07001026 def check_clash(self, info, seen):
1027 cname = c_name(self.name)
Eric Blake893e1f22015-12-01 22:20:57 -07001028 if cname.lower() != cname and self.owner not in case_whitelist:
1029 raise QAPIExprError(info,
1030 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001031 if cname in seen:
1032 raise QAPIExprError(info,
1033 "%s collides with %s"
1034 % (self.describe(), seen[cname].describe()))
1035 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001036
Eric Blake88d4ef82015-11-18 01:52:50 -07001037 def _pretty_owner(self):
1038 owner = self.owner
Eric Blake75996972016-03-17 16:48:29 -06001039 if owner.startswith('q_obj_'):
Eric Blake88d4ef82015-11-18 01:52:50 -07001040 # See QAPISchema._make_implicit_object_type() - reverse the
1041 # mapping there to create a nice human-readable description
Eric Blake75996972016-03-17 16:48:29 -06001042 owner = owner[6:]
Eric Blake88d4ef82015-11-18 01:52:50 -07001043 if owner.endswith('-arg'):
1044 return '(parameter of %s)' % owner[:-4]
Eric Blakeac4338f2016-03-17 16:48:39 -06001045 elif owner.endswith('-base'):
1046 return '(base of %s)' % owner[:-5]
Eric Blake88d4ef82015-11-18 01:52:50 -07001047 else:
1048 assert owner.endswith('-wrapper')
1049 # Unreachable and not implemented
1050 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001051 if owner.endswith('Kind'):
1052 # See QAPISchema._make_implicit_enum_type()
1053 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001054 return '(%s of %s)' % (self.role, owner)
1055
1056 def describe(self):
1057 return "'%s' %s" % (self.name, self._pretty_owner())
1058
Markus Armbrusterac882192015-09-16 13:06:05 +02001059
Eric Blaked44f9ac2015-12-01 22:20:54 -07001060class QAPISchemaObjectTypeMember(QAPISchemaMember):
1061 def __init__(self, name, typ, optional):
1062 QAPISchemaMember.__init__(self, name)
1063 assert isinstance(typ, str)
1064 assert isinstance(optional, bool)
1065 self._type_name = typ
1066 self.type = None
1067 self.optional = optional
1068
1069 def check(self, schema):
1070 assert self.owner
1071 self.type = schema.lookup_type(self._type_name)
1072 assert self.type
1073
1074
Markus Armbrusterac882192015-09-16 13:06:05 +02001075class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001076 def __init__(self, tag_name, tag_member, variants):
1077 # Flat unions pass tag_name but not tag_member.
1078 # Simple unions and alternates pass tag_member but not tag_name.
1079 # After check(), tag_member is always set, and tag_name remains
1080 # a reliable witness of being used by a flat union.
1081 assert bool(tag_member) != bool(tag_name)
1082 assert (isinstance(tag_name, str) or
1083 isinstance(tag_member, QAPISchemaObjectTypeMember))
Eric Blake02a57ae2016-02-17 23:48:16 -07001084 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001085 for v in variants:
1086 assert isinstance(v, QAPISchemaObjectTypeVariant)
1087 self.tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001088 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001089 self.variants = variants
1090
Eric Blake88d4ef82015-11-18 01:52:50 -07001091 def set_owner(self, name):
1092 for v in self.variants:
1093 v.set_owner(name)
1094
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001095 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001096 if not self.tag_member: # flat union
Eric Blake27b60ab2015-11-18 01:52:51 -07001097 self.tag_member = seen[c_name(self.tag_name)]
1098 assert self.tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001099 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1100 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001101 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001102 # Union names must match enum values; alternate names are
1103 # checked separately. Use 'seen' to tell the two apart.
1104 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001105 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001106 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001107 v.type.check(schema)
1108
Eric Blake27b60ab2015-11-18 01:52:51 -07001109 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001110 for v in self.variants:
1111 # Reset seen map for each variant, since qapi names from one
1112 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001113 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001114 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001115
Eric Blake437db252015-09-29 16:21:02 -06001116
Markus Armbrusterac882192015-09-16 13:06:05 +02001117class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001118 role = 'branch'
1119
Markus Armbrusterac882192015-09-16 13:06:05 +02001120 def __init__(self, name, typ):
1121 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1122
Markus Armbrusterac882192015-09-16 13:06:05 +02001123
1124class QAPISchemaAlternateType(QAPISchemaType):
1125 def __init__(self, name, info, variants):
1126 QAPISchemaType.__init__(self, name, info)
1127 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1128 assert not variants.tag_name
Eric Blake88d4ef82015-11-18 01:52:50 -07001129 variants.set_owner(name)
1130 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001131 self.variants = variants
1132
1133 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001134 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001135 # Not calling self.variants.check_clash(), because there's nothing
1136 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001137 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001138 # Alternate branch names have no relation to the tag enum values;
1139 # so we have to check for potential name collisions ourselves.
1140 seen = {}
1141 for v in self.variants.variants:
1142 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001143
Eric Blake4040d992016-03-17 16:48:28 -06001144 def c_type(self):
1145 return c_name(self.name) + pointer_suffix
1146
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001147 def json_type(self):
1148 return 'value'
1149
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001150 def visit(self, visitor):
1151 visitor.visit_alternate_type(self.name, self.info, self.variants)
1152
Markus Armbrusterac882192015-09-16 13:06:05 +02001153
1154class QAPISchemaCommand(QAPISchemaEntity):
1155 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1156 QAPISchemaEntity.__init__(self, name, info)
1157 assert not arg_type or isinstance(arg_type, str)
1158 assert not ret_type or isinstance(ret_type, str)
1159 self._arg_type_name = arg_type
1160 self.arg_type = None
1161 self._ret_type_name = ret_type
1162 self.ret_type = None
1163 self.gen = gen
1164 self.success_response = success_response
1165
1166 def check(self, schema):
1167 if self._arg_type_name:
1168 self.arg_type = schema.lookup_type(self._arg_type_name)
1169 assert isinstance(self.arg_type, QAPISchemaObjectType)
1170 assert not self.arg_type.variants # not implemented
1171 if self._ret_type_name:
1172 self.ret_type = schema.lookup_type(self._ret_type_name)
1173 assert isinstance(self.ret_type, QAPISchemaType)
1174
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001175 def visit(self, visitor):
1176 visitor.visit_command(self.name, self.info,
1177 self.arg_type, self.ret_type,
1178 self.gen, self.success_response)
1179
Markus Armbrusterac882192015-09-16 13:06:05 +02001180
1181class QAPISchemaEvent(QAPISchemaEntity):
1182 def __init__(self, name, info, arg_type):
1183 QAPISchemaEntity.__init__(self, name, info)
1184 assert not arg_type or isinstance(arg_type, str)
1185 self._arg_type_name = arg_type
1186 self.arg_type = None
1187
1188 def check(self, schema):
1189 if self._arg_type_name:
1190 self.arg_type = schema.lookup_type(self._arg_type_name)
1191 assert isinstance(self.arg_type, QAPISchemaObjectType)
1192 assert not self.arg_type.variants # not implemented
1193
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001194 def visit(self, visitor):
1195 visitor.visit_event(self.name, self.info, self.arg_type)
1196
Markus Armbrusterac882192015-09-16 13:06:05 +02001197
1198class QAPISchema(object):
1199 def __init__(self, fname):
1200 try:
1201 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
Eric Blake7618b912015-10-12 22:22:22 -06001202 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001203 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001204 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001205 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001206 self._def_exprs()
1207 self.check()
Markus Armbruster291928a2015-12-18 08:52:41 +01001208 except (QAPISchemaError, QAPIExprError) as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001209 print >>sys.stderr, err
1210 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001211
Markus Armbrusterac882192015-09-16 13:06:05 +02001212 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001213 # Only the predefined types are allowed to not have info
1214 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001215 assert ent.name not in self._entity_dict
1216 self._entity_dict[ent.name] = ent
1217
1218 def lookup_entity(self, name, typ=None):
1219 ent = self._entity_dict.get(name)
1220 if typ and not isinstance(ent, typ):
1221 return None
1222 return ent
1223
1224 def lookup_type(self, name):
1225 return self.lookup_entity(name, QAPISchemaType)
1226
Eric Blake861877a2016-03-17 16:48:36 -06001227 def _def_builtin_type(self, name, json_type, c_type):
1228 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001229 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1230 # qapi-types.h from a single .c, all arrays of builtins must be
1231 # declared in the first file whether or not they are used. Nicer
1232 # would be to use lazy instantiation, while figuring out how to
1233 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001234 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001235
1236 def _def_predefineds(self):
Eric Blake861877a2016-03-17 16:48:36 -06001237 for t in [('str', 'string', 'char' + pointer_suffix),
1238 ('number', 'number', 'double'),
1239 ('int', 'int', 'int64_t'),
1240 ('int8', 'int', 'int8_t'),
1241 ('int16', 'int', 'int16_t'),
1242 ('int32', 'int', 'int32_t'),
1243 ('int64', 'int', 'int64_t'),
1244 ('uint8', 'int', 'uint8_t'),
1245 ('uint16', 'int', 'uint16_t'),
1246 ('uint32', 'int', 'uint32_t'),
1247 ('uint64', 'int', 'uint64_t'),
1248 ('size', 'int', 'uint64_t'),
1249 ('bool', 'boolean', 'bool'),
1250 ('any', 'value', 'QObject' + pointer_suffix)]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001251 self._def_builtin_type(*t)
Eric Blake75996972016-03-17 16:48:29 -06001252 self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1253 None, [], None)
Markus Armbruster39a18152015-09-16 13:06:28 +02001254 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001255 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1256 'qstring', 'qdict', 'qlist',
1257 'qfloat', 'qbool'])
1258 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001259 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001260
Eric Blake93bda4d2015-12-01 22:20:55 -07001261 def _make_enum_members(self, values):
1262 return [QAPISchemaMember(v) for v in values]
1263
Eric Blake99df5282015-10-12 22:22:32 -06001264 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001265 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001266 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001267 self._def_entity(QAPISchemaEnumType(
1268 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001269 return name
1270
Eric Blake99df5282015-10-12 22:22:32 -06001271 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001272 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001273 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001274 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001275 return name
1276
Eric Blake99df5282015-10-12 22:22:32 -06001277 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001278 if not members:
1279 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001280 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake75996972016-03-17 16:48:29 -06001281 name = 'q_obj_%s-%s' % (name, role)
Markus Armbrusterac882192015-09-16 13:06:05 +02001282 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001283 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001284 members, None))
1285 return name
1286
1287 def _def_enum_type(self, expr, info):
1288 name = expr['enum']
1289 data = expr['data']
1290 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001291 self._def_entity(QAPISchemaEnumType(
1292 name, info, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001293
Eric Blake99df5282015-10-12 22:22:32 -06001294 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001295 optional = False
1296 if name.startswith('*'):
1297 name = name[1:]
1298 optional = True
1299 if isinstance(typ, list):
1300 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001301 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001302 return QAPISchemaObjectTypeMember(name, typ, optional)
1303
Eric Blake99df5282015-10-12 22:22:32 -06001304 def _make_members(self, data, info):
1305 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001306 for (key, value) in data.iteritems()]
1307
1308 def _def_struct_type(self, expr, info):
1309 name = expr['struct']
1310 base = expr.get('base')
1311 data = expr['data']
1312 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001313 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001314 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001315
1316 def _make_variant(self, case, typ):
1317 return QAPISchemaObjectTypeVariant(case, typ)
1318
Eric Blake99df5282015-10-12 22:22:32 -06001319 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001320 if isinstance(typ, list):
1321 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001322 typ = self._make_array_type(typ[0], info)
1323 typ = self._make_implicit_object_type(
1324 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001325 return QAPISchemaObjectTypeVariant(case, typ)
1326
Markus Armbrusterac882192015-09-16 13:06:05 +02001327 def _def_union_type(self, expr, info):
1328 name = expr['union']
1329 data = expr['data']
1330 base = expr.get('base')
1331 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001332 tag_member = None
Eric Blakeac4338f2016-03-17 16:48:39 -06001333 if isinstance(base, dict):
1334 base = (self._make_implicit_object_type(
1335 name, info, 'base', self._make_members(base, info)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001336 if tag_name:
1337 variants = [self._make_variant(key, value)
1338 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001339 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001340 else:
Eric Blake99df5282015-10-12 22:22:32 -06001341 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001342 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001343 typ = self._make_implicit_enum_type(name, info,
1344 [v.name for v in variants])
1345 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001346 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001347 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001348 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001349 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001350 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001351 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001352
1353 def _def_alternate_type(self, expr, info):
1354 name = expr['alternate']
1355 data = expr['data']
1356 variants = [self._make_variant(key, value)
1357 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001358 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001359 self._def_entity(
1360 QAPISchemaAlternateType(name, info,
1361 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001362 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001363 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001364
1365 def _def_command(self, expr, info):
1366 name = expr['command']
1367 data = expr.get('data')
1368 rets = expr.get('returns')
1369 gen = expr.get('gen', True)
1370 success_response = expr.get('success-response', True)
1371 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001372 data = self._make_implicit_object_type(
1373 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001374 if isinstance(rets, list):
1375 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001376 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001377 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1378 success_response))
1379
1380 def _def_event(self, expr, info):
1381 name = expr['event']
1382 data = expr.get('data')
1383 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001384 data = self._make_implicit_object_type(
1385 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001386 self._def_entity(QAPISchemaEvent(name, info, data))
1387
1388 def _def_exprs(self):
1389 for expr_elem in self.exprs:
1390 expr = expr_elem['expr']
1391 info = expr_elem['info']
1392 if 'enum' in expr:
1393 self._def_enum_type(expr, info)
1394 elif 'struct' in expr:
1395 self._def_struct_type(expr, info)
1396 elif 'union' in expr:
1397 self._def_union_type(expr, info)
1398 elif 'alternate' in expr:
1399 self._def_alternate_type(expr, info)
1400 elif 'command' in expr:
1401 self._def_command(expr, info)
1402 elif 'event' in expr:
1403 self._def_event(expr, info)
1404 else:
1405 assert False
1406
1407 def check(self):
1408 for ent in self._entity_dict.values():
1409 ent.check(self)
1410
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001411 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001412 visitor.visit_begin(self)
1413 for (name, entity) in sorted(self._entity_dict.items()):
1414 if visitor.visit_needed(entity):
1415 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001416 visitor.visit_end()
1417
Markus Armbruster2caba362013-07-27 17:41:56 +02001418
Markus Armbruster00e4b282015-06-10 10:04:36 +02001419#
1420# Code generation helpers
1421#
1422
Michael Roth0f923be2011-07-19 14:50:39 -05001423def camel_case(name):
1424 new_name = ''
1425 first = True
1426 for ch in name:
1427 if ch in ['_', '-']:
1428 first = True
1429 elif first:
1430 new_name += ch.upper()
1431 first = False
1432 else:
1433 new_name += ch.lower()
1434 return new_name
1435
Eric Blake437db252015-09-29 16:21:02 -06001436
Markus Armbruster849bc532015-05-14 06:50:53 -06001437# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1438# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1439# ENUM24_Name -> ENUM24_NAME
1440def camel_to_upper(value):
1441 c_fun_str = c_name(value, False)
1442 if value.isupper():
1443 return c_fun_str
1444
1445 new_name = ''
1446 l = len(c_fun_str)
1447 for i in range(l):
1448 c = c_fun_str[i]
1449 # When c is upper and no "_" appears before, do more checks
1450 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001451 if i < l - 1 and c_fun_str[i + 1].islower():
1452 new_name += '_'
1453 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001454 new_name += '_'
1455 new_name += c
1456 return new_name.lstrip('_').upper()
1457
Eric Blake437db252015-09-29 16:21:02 -06001458
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001459def c_enum_const(type_name, const_name, prefix=None):
1460 if prefix is not None:
1461 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001462 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001463
Eric Blake18df5152015-05-14 06:50:48 -06001464c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001465
Eric Blake437db252015-09-29 16:21:02 -06001466
Eric Blakec6405b52015-05-14 06:50:55 -06001467# Map @name to a valid C identifier.
1468# If @protect, avoid returning certain ticklish identifiers (like
1469# C keywords) by prepending "q_".
1470#
1471# Used for converting 'name' from a 'name':'type' qapi definition
1472# into a generated struct member, as well as converting type names
1473# into substrings of a generated C function name.
1474# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1475# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001476def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001477 # ANSI X3J11/88-090, 3.1.1
1478 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001479 'default', 'do', 'double', 'else', 'enum', 'extern',
1480 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1481 'return', 'short', 'signed', 'sizeof', 'static',
1482 'struct', 'switch', 'typedef', 'union', 'unsigned',
1483 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001484 # ISO/IEC 9899:1999, 6.4.1
1485 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1486 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001487 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1488 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001489 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1490 # excluding _.*
1491 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001492 # C++ ISO/IEC 14882:2003 2.11
1493 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1494 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1495 'namespace', 'new', 'operator', 'private', 'protected',
1496 'public', 'reinterpret_cast', 'static_cast', 'template',
1497 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1498 'using', 'virtual', 'wchar_t',
1499 # alternative representations
1500 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1501 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001502 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001503 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001504 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001505 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1506 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001507 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001508 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001509
Amos Kong05dfb262014-06-10 19:25:53 +08001510eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001511pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001512
Eric Blake437db252015-09-29 16:21:02 -06001513
Michael Roth0f923be2011-07-19 14:50:39 -05001514def genindent(count):
1515 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001516 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001517 ret += " "
1518 return ret
1519
1520indent_level = 0
1521
Eric Blake437db252015-09-29 16:21:02 -06001522
Michael Roth0f923be2011-07-19 14:50:39 -05001523def push_indent(indent_amount=4):
1524 global indent_level
1525 indent_level += indent_amount
1526
Eric Blake437db252015-09-29 16:21:02 -06001527
Michael Roth0f923be2011-07-19 14:50:39 -05001528def pop_indent(indent_amount=4):
1529 global indent_level
1530 indent_level -= indent_amount
1531
Eric Blake437db252015-09-29 16:21:02 -06001532
Markus Armbruster77e703b2015-06-24 19:27:32 +02001533# Generate @code with @kwds interpolated.
1534# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001535def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001536 raw = code % kwds
1537 if indent_level:
1538 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001539 # re.subn() lacks flags support before Python 2.7, use re.compile()
1540 raw = re.subn(re.compile("^.", re.MULTILINE),
1541 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001542 raw = raw[0]
1543 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001544
Eric Blake437db252015-09-29 16:21:02 -06001545
Michael Roth0f923be2011-07-19 14:50:39 -05001546def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001547 if code[0] == '\n':
1548 code = code[1:]
1549 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001550
Michael Roth0f923be2011-07-19 14:50:39 -05001551
1552def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001553 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001554
Eric Blake437db252015-09-29 16:21:02 -06001555
Michael Rothc0afa9c2013-05-10 17:46:00 -05001556def guardstart(name):
1557 return mcgen('''
1558
1559#ifndef %(name)s
1560#define %(name)s
1561
1562''',
1563 name=guardname(name))
1564
Eric Blake437db252015-09-29 16:21:02 -06001565
Michael Rothc0afa9c2013-05-10 17:46:00 -05001566def guardend(name):
1567 return mcgen('''
1568
1569#endif /* %(name)s */
1570
1571''',
1572 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001573
Eric Blake437db252015-09-29 16:21:02 -06001574
Markus Armbrustere98859a2015-09-16 13:06:16 +02001575def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001576 ret = mcgen('''
1577
Markus Armbrustere98859a2015-09-16 13:06:16 +02001578const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001579''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001580 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001581 for value in values:
1582 index = c_enum_const(name, value, prefix)
1583 ret += mcgen('''
1584 [%(index)s] = "%(value)s",
1585''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001586 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001587
Eric Blake7fb1cf12015-11-18 01:52:57 -07001588 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001589 ret += mcgen('''
1590 [%(max_index)s] = NULL,
1591};
1592''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001593 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001594 return ret
1595
Eric Blake437db252015-09-29 16:21:02 -06001596
Markus Armbrustere98859a2015-09-16 13:06:16 +02001597def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001598 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001599 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001600
1601 ret = mcgen('''
1602
1603typedef enum %(c_name)s {
1604''',
1605 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001606
1607 i = 0
1608 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001609 ret += mcgen('''
1610 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001611''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001612 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001613 i=i)
1614 i += 1
1615
Markus Armbrustere98859a2015-09-16 13:06:16 +02001616 ret += mcgen('''
1617} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001618''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001619 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001620
Markus Armbrustere98859a2015-09-16 13:06:16 +02001621 ret += mcgen('''
1622
1623extern const char *const %(c_name)s_lookup[];
1624''',
1625 c_name=c_name(name))
1626 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001627
Eric Blake437db252015-09-29 16:21:02 -06001628
Markus Armbruster03b43672015-09-16 13:06:20 +02001629def gen_params(arg_type, extra):
1630 if not arg_type:
1631 return extra
1632 assert not arg_type.variants
1633 ret = ''
1634 sep = ''
1635 for memb in arg_type.members:
1636 ret += sep
1637 sep = ', '
1638 if memb.optional:
1639 ret += 'bool has_%s, ' % c_name(memb.name)
Eric Blake4040d992016-03-17 16:48:28 -06001640 ret += '%s %s' % (memb.type.c_param_type(), c_name(memb.name))
Markus Armbruster03b43672015-09-16 13:06:20 +02001641 if extra:
1642 ret += sep + extra
1643 return ret
1644
Eric Blake1f353342015-09-29 16:21:13 -06001645
Eric Blake12f254f2016-03-17 16:48:35 -06001646def gen_err_check():
Eric Blake1f353342015-09-29 16:21:13 -06001647 return mcgen('''
Eric Blake18bdbc32015-09-29 16:21:15 -06001648 if (err) {
Eric Blake12f254f2016-03-17 16:48:35 -06001649 goto out;
Eric Blake82ca8e42015-09-29 16:21:14 -06001650 }
1651''')
Eric Blake82ca8e42015-09-29 16:21:14 -06001652
1653
Markus Armbruster00e4b282015-06-10 10:04:36 +02001654#
1655# Common command line parsing
1656#
1657
Eric Blake437db252015-09-29 16:21:02 -06001658
1659def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001660
1661 try:
1662 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001663 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001664 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001665 "output-dir="] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001666 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001667 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001668 sys.exit(1)
1669
1670 output_dir = ""
1671 prefix = ""
1672 do_c = False
1673 do_h = False
1674 extra_opts = []
1675
1676 for oa in opts:
1677 o, a = oa
1678 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001679 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1680 if match.end() != len(a):
1681 print >>sys.stderr, \
1682 "%s: 'funny character '%s' in argument of --prefix" \
1683 % (sys.argv[0], a[match.end()])
1684 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001685 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001686 elif o in ("-o", "--output-dir"):
1687 output_dir = a + "/"
1688 elif o in ("-c", "--source"):
1689 do_c = True
1690 elif o in ("-h", "--header"):
1691 do_h = True
1692 else:
1693 extra_opts.append(oa)
1694
1695 if not do_c and not do_h:
1696 do_c = True
1697 do_h = True
1698
Markus Armbruster16d80f62015-04-02 13:32:16 +02001699 if len(args) != 1:
1700 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001701 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001702 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001703
Markus Armbruster54414042015-06-09 16:22:45 +02001704 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001705
Markus Armbruster00e4b282015-06-10 10:04:36 +02001706#
1707# Generate output files with boilerplate
1708#
1709
Eric Blake437db252015-09-29 16:21:02 -06001710
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001711def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1712 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001713 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001714 c_file = output_dir + prefix + c_file
1715 h_file = output_dir + prefix + h_file
1716
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001717 if output_dir:
1718 try:
1719 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01001720 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001721 if e.errno != errno.EEXIST:
1722 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001723
1724 def maybe_open(really, name, opt):
1725 if really:
1726 return open(name, opt)
1727 else:
1728 import StringIO
1729 return StringIO.StringIO()
1730
1731 fdef = maybe_open(do_c, c_file, 'w')
1732 fdecl = maybe_open(do_h, h_file, 'w')
1733
1734 fdef.write(mcgen('''
1735/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1736%(comment)s
1737''',
Eric Blake437db252015-09-29 16:21:02 -06001738 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001739
1740 fdecl.write(mcgen('''
1741/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1742%(comment)s
1743#ifndef %(guard)s
1744#define %(guard)s
1745
1746''',
Eric Blake437db252015-09-29 16:21:02 -06001747 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001748
1749 return (fdef, fdecl)
1750
Eric Blake437db252015-09-29 16:21:02 -06001751
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001752def close_output(fdef, fdecl):
1753 fdecl.write('''
1754#endif
1755''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001756 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001757 fdef.close()