blob: 1483ec09f5a8ef9a4289ed8a67b1adcc6e7088e3 [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
Marc-André Lureau4148c292017-01-13 15:41:25 +010094class QAPIError(Exception):
95 def __init__(self, fname, line, col, incl_info, msg):
Eric Blake59b00542015-09-29 16:21:01 -060096 Exception.__init__(self)
Marc-André Lureau4148c292017-01-13 15:41:25 +010097 self.fname = fname
98 self.line = line
99 self.col = col
100 self.info = incl_info
Markus Armbruster2caba362013-07-27 17:41:56 +0200101 self.msg = msg
Marc-André Lureau4148c292017-01-13 15:41:25 +0100102
103 def __str__(self):
104 loc = "%s:%d" % (self.fname, self.line)
105 if self.col is not None:
106 loc += ":%s" % self.col
107 return error_path(self.info) + "%s: %s" % (loc, self.msg)
108
109
110class QAPIParseError(QAPIError):
111 def __init__(self, parser, msg):
112 col = 1
113 for ch in parser.src[parser.line_pos:parser.pos]:
Wenchao Xia515b9432014-03-04 18:44:33 -0800114 if ch == '\t':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100115 col = (col + 7) % 8 + 1
Markus Armbruster2caba362013-07-27 17:41:56 +0200116 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100117 col += 1
118 QAPIError.__init__(self, parser.fname, parser.line, col,
119 parser.incl_info, msg)
Markus Armbruster2caba362013-07-27 17:41:56 +0200120
Eric Blake437db252015-09-29 16:21:02 -0600121
Marc-André Lureau4148c292017-01-13 15:41:25 +0100122class QAPISemError(QAPIError):
123 def __init__(self, info, msg):
124 QAPIError.__init__(self, info['file'], info['line'], None,
125 info['parent'], msg)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800126
Eric Blake437db252015-09-29 16:21:02 -0600127
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200128class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500129
Eric Blake437db252015-09-29 16:21:02 -0600130 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200131 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200132 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200133 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200134 previously_included.append(abs_fname)
135 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200136 self.src = fp.read()
137 if self.src == '' or self.src[-1] != '\n':
138 self.src += '\n'
139 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800140 self.line = 1
141 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200142 self.exprs = []
143 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500144
Eric Blake437db252015-09-29 16:21:02 -0600145 while self.tok is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100146 info = {'file': fname, 'line': self.line,
147 'parent': self.incl_info}
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200148 expr = self.get_expr(False)
149 if isinstance(expr, dict) and "include" in expr:
150 if len(expr) != 1:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100151 raise QAPISemError(info, "Invalid 'include' directive")
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200152 include = expr["include"]
153 if not isinstance(include, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100154 raise QAPISemError(info,
155 "Value of 'include' must be a string")
Markus Armbruster54414042015-06-09 16:22:45 +0200156 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
157 include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200158 # catch inclusion cycle
Marc-André Lureau4148c292017-01-13 15:41:25 +0100159 inf = info
Markus Armbrustera1366082015-06-09 16:54:09 +0200160 while inf:
161 if incl_abs_fname == os.path.abspath(inf['file']):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100162 raise QAPISemError(info, "Inclusion loop for %s"
163 % include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200164 inf = inf['parent']
Benoît Canet24fd8482014-05-16 12:51:56 +0200165 # skip multiple include of the same file
Markus Armbruster54414042015-06-09 16:22:45 +0200166 if incl_abs_fname in previously_included:
Benoît Canet24fd8482014-05-16 12:51:56 +0200167 continue
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200168 try:
Markus Armbruster54414042015-06-09 16:22:45 +0200169 fobj = open(incl_abs_fname, 'r')
Markus Armbruster291928a2015-12-18 08:52:41 +0100170 except IOError as e:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100171 raise QAPISemError(info, '%s: %s' % (e.strerror, include))
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200172 exprs_include = QAPISchemaParser(fobj, previously_included,
Marc-André Lureau4148c292017-01-13 15:41:25 +0100173 info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200174 self.exprs.extend(exprs_include.exprs)
175 else:
176 expr_elem = {'expr': expr,
Marc-André Lureau4148c292017-01-13 15:41:25 +0100177 'info': info}
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200178 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500179
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200180 def accept(self):
181 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200182 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200183 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200184 self.cursor += 1
185 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500186
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200187 if self.tok == '#':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200188 self.cursor = self.src.find('\n', self.cursor)
Eric Blake8712fa52015-10-26 16:34:41 -0600189 elif self.tok in "{}:,[]":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200190 return
191 elif self.tok == "'":
192 string = ''
193 esc = False
194 while True:
195 ch = self.src[self.cursor]
196 self.cursor += 1
197 if ch == '\n':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100198 raise QAPIParseError(self, '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":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100216 raise QAPIParseError(self,
217 '\\u escape needs 4 '
218 'hex digits')
Eric Blakea7f59662015-05-04 09:05:36 -0600219 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:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100225 raise QAPIParseError(self,
226 'For now, \\u escape '
227 'only supports non-zero '
228 'values up to \\u007f')
Eric Blakea7f59662015-05-04 09:05:36 -0600229 string += chr(value)
230 elif ch in "\\/'\"":
231 string += ch
232 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100233 raise QAPIParseError(self,
234 "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():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100262 raise QAPIParseError(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 != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100270 raise QAPIParseError(self, 'Expected string or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200271 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 != ':':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100275 raise QAPIParseError(self, 'Expected ":"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200276 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800277 if key in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100278 raise QAPIParseError(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 != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100284 raise QAPIParseError(self, 'Expected "," or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200285 self.accept()
286 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100287 raise QAPIParseError(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":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100295 raise QAPIParseError(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 != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100303 raise QAPIParseError(self, 'Expected "," or "]"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200304 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:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100308 raise QAPIParseError(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:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100319 raise QAPIParseError(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
Marc-André Lureau4148c292017-01-13 15:41:25 +0100378def check_name(info, source, name, allow_optional=False,
Eric Blake437db252015-09-29 16:21:02 -0600379 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600380 global valid_name
381 membername = name
382
383 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100384 raise QAPISemError(info, "%s requires a string name" % source)
Eric Blakec9e0a792015-05-04 09:05:22 -0600385 if name.startswith('*'):
386 membername = name[1:]
387 if not allow_optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100388 raise QAPISemError(info, "%s does not allow optional name '%s'"
389 % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600390 # Enum members can start with a digit, because the generated C
391 # code always prefixes it with the enum name
Eric Blake59a92fe2015-11-18 01:52:56 -0700392 if enum_member and membername[0].isdigit():
393 membername = 'D' + membername
Eric Blake75996972016-03-17 16:48:29 -0600394 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
395 # and 'q_obj_*' implicit type names.
Eric Blake9fb081e2015-10-26 16:34:44 -0600396 if not valid_name.match(membername) or \
397 c_name(membername, False).startswith('q_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100398 raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600399
Eric Blake437db252015-09-29 16:21:02 -0600400
401def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200402 global all_names
403 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200404 # FIXME should reject names that differ only in '_' vs. '.'
405 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200406 if name in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100407 raise QAPISemError(info, "%s '%s' is already defined"
408 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600409 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100410 raise QAPISemError(info, "%s '%s' should not end in '%s'"
411 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200412 all_names[name] = meta
413
Eric Blake437db252015-09-29 16:21:02 -0600414
Markus Armbruster00e4b282015-06-10 10:04:36 +0200415def add_struct(definition, info):
416 global struct_types
417 name = definition['struct']
418 add_name(name, info, 'struct')
419 struct_types.append(definition)
420
Eric Blake437db252015-09-29 16:21:02 -0600421
Markus Armbruster00e4b282015-06-10 10:04:36 +0200422def find_struct(name):
423 global struct_types
424 for struct in struct_types:
425 if struct['struct'] == name:
426 return struct
427 return None
428
Eric Blake437db252015-09-29 16:21:02 -0600429
Markus Armbruster00e4b282015-06-10 10:04:36 +0200430def add_union(definition, info):
431 global union_types
432 name = definition['union']
433 add_name(name, info, 'union')
434 union_types.append(definition)
435
Eric Blake437db252015-09-29 16:21:02 -0600436
Markus Armbruster00e4b282015-06-10 10:04:36 +0200437def find_union(name):
438 global union_types
439 for union in union_types:
440 if union['union'] == name:
441 return union
442 return None
443
Eric Blake437db252015-09-29 16:21:02 -0600444
445def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200446 global enum_types
447 add_name(name, info, 'enum', implicit)
448 enum_types.append({"enum_name": name, "enum_values": enum_values})
449
Eric Blake437db252015-09-29 16:21:02 -0600450
Markus Armbruster00e4b282015-06-10 10:04:36 +0200451def find_enum(name):
452 global enum_types
453 for enum in enum_types:
454 if enum['enum_name'] == name:
455 return enum
456 return None
457
Markus Armbruster00e4b282015-06-10 10:04:36 +0200458
Eric Blake437db252015-09-29 16:21:02 -0600459def is_enum(name):
460 return find_enum(name) is not None
461
462
Marc-André Lureau4148c292017-01-13 15:41:25 +0100463def check_type(info, source, value, allow_array=False,
Eric Blake437db252015-09-29 16:21:02 -0600464 allow_dict=False, allow_optional=False,
465 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600466 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600467
468 if value is None:
469 return
470
Eric Blakedd883c62015-05-04 09:05:21 -0600471 # Check if array type for value is okay
472 if isinstance(value, list):
473 if not allow_array:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100474 raise QAPISemError(info, "%s cannot be an array" % source)
Eric Blakedd883c62015-05-04 09:05:21 -0600475 if len(value) != 1 or not isinstance(value[0], str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100476 raise QAPISemError(info,
477 "%s: array type must contain single type name" %
478 source)
Eric Blakedd883c62015-05-04 09:05:21 -0600479 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600480
481 # Check if type name for value is okay
482 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600483 if value not in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100484 raise QAPISemError(info, "%s uses unknown type '%s'"
485 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600486 if not all_names[value] in allow_metas:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100487 raise QAPISemError(info, "%s cannot use %s type '%s'" %
488 (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600489 return
490
Eric Blakedd883c62015-05-04 09:05:21 -0600491 if not allow_dict:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100492 raise QAPISemError(info, "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200493
494 if not isinstance(value, OrderedDict):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100495 raise QAPISemError(info,
496 "%s should be a dictionary or type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200497
498 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600499 for (key, arg) in value.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100500 check_name(info, "Member of %s" % source, key,
Eric Blakec9e0a792015-05-04 09:05:22 -0600501 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600502 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100503 raise QAPISemError(info, "Member of %s uses reserved name '%s'"
504 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600505 # Todo: allow dictionaries to represent default values of
506 # an optional argument.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100507 check_type(info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200508 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600509 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600510 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600511
Eric Blake437db252015-09-29 16:21:02 -0600512
Marc-André Lureau4148c292017-01-13 15:41:25 +0100513def check_command(expr, info):
Eric Blakedd883c62015-05-04 09:05:21 -0600514 name = expr['command']
Eric Blakec8184082016-07-13 21:50:20 -0600515 boxed = expr.get('boxed', False)
Eric Blake2cbf0992015-05-04 09:05:24 -0600516
Eric Blakec8184082016-07-13 21:50:20 -0600517 args_meta = ['struct']
518 if boxed:
519 args_meta += ['union', 'alternate']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100520 check_type(info, "'data' for command '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600521 expr.get('data'), allow_dict=not boxed, allow_optional=True,
522 allow_metas=args_meta)
Eric Blake10d4d992015-05-04 09:05:23 -0600523 returns_meta = ['union', 'struct']
524 if name in returns_whitelist:
525 returns_meta += ['built-in', 'alternate', 'enum']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100526 check_type(info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200527 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200528 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600529
Eric Blake437db252015-09-29 16:21:02 -0600530
Marc-André Lureau4148c292017-01-13 15:41:25 +0100531def check_event(expr, info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600532 global events
533 name = expr['event']
Eric Blakec8184082016-07-13 21:50:20 -0600534 boxed = expr.get('boxed', False)
Eric Blake4dc2e692015-05-04 09:05:17 -0600535
Eric Blakec8184082016-07-13 21:50:20 -0600536 meta = ['struct']
537 if boxed:
538 meta += ['union', 'alternate']
Eric Blake4dc2e692015-05-04 09:05:17 -0600539 events.append(name)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100540 check_type(info, "'data' for event '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600541 expr.get('data'), allow_dict=not boxed, allow_optional=True,
542 allow_metas=meta)
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200543
Eric Blake437db252015-09-29 16:21:02 -0600544
Marc-André Lureau4148c292017-01-13 15:41:25 +0100545def check_union(expr, info):
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800546 name = expr['union']
547 base = expr.get('base')
548 discriminator = expr.get('discriminator')
549 members = expr['data']
550
Eric Blake811d04f2015-05-04 09:05:10 -0600551 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600552
553 # With no discriminator it is a simple union.
554 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600555 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600556 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600557 if base is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100558 raise QAPISemError(info, "Simple union '%s' must not have a base" %
559 name)
Eric Blake44bd1272015-05-04 09:05:08 -0600560
561 # Else, it's a flat union.
562 else:
Eric Blakeac4338f2016-03-17 16:48:39 -0600563 # The object must have a string or dictionary 'base'.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100564 check_type(info, "'base' for union '%s'" % name,
Eric Blakeac4338f2016-03-17 16:48:39 -0600565 base, allow_dict=True, allow_optional=True,
566 allow_metas=['struct'])
Eric Blake376863e2015-09-29 16:21:07 -0600567 if not base:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100568 raise QAPISemError(info, "Flat union '%s' must have a base"
569 % name)
Eric Blake14f00c62016-03-03 09:16:43 -0700570 base_members = find_base_members(base)
571 assert base_members
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800572
Eric Blakec9e0a792015-05-04 09:05:22 -0600573 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600574 # member of the base struct.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100575 check_name(info, "Discriminator of flat union '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600576 discriminator)
Eric Blake14f00c62016-03-03 09:16:43 -0700577 discriminator_type = base_members.get(discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800578 if not discriminator_type:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100579 raise QAPISemError(info,
580 "Discriminator '%s' is not a member of base "
581 "struct '%s'"
582 % (discriminator, base))
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800583 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600584 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800585 # Do not allow string discriminator
586 if not enum_define:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100587 raise QAPISemError(info,
588 "Discriminator '%s' must be of enumeration "
589 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800590
Eric Blake02a57ae2016-02-17 23:48:16 -0700591 # Check every branch; don't allow an empty union
592 if len(members) == 0:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100593 raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800594 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100595 check_name(info, "Member of union '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600596
Eric Blake01cfbaa2015-12-01 22:20:58 -0700597 # Each value must name a known type
Marc-André Lureau4148c292017-01-13 15:41:25 +0100598 check_type(info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200599 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakedd883c62015-05-04 09:05:21 -0600600
Eric Blake44bd1272015-05-04 09:05:08 -0600601 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700602 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600603 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600604 if key not in enum_define['enum_values']:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100605 raise QAPISemError(info,
606 "Discriminator value '%s' is not found in "
607 "enum '%s'"
608 % (key, enum_define["enum_name"]))
Eric Blake44bd1272015-05-04 09:05:08 -0600609
Eric Blaked0b18232016-07-13 21:50:13 -0600610 # If discriminator is user-defined, ensure all values are covered
611 if enum_define:
612 for value in enum_define['enum_values']:
613 if value not in members.keys():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100614 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
615 % (name, value))
Eric Blaked0b18232016-07-13 21:50:13 -0600616
Eric Blake437db252015-09-29 16:21:02 -0600617
Marc-André Lureau4148c292017-01-13 15:41:25 +0100618def check_alternate(expr, info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600619 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600620 members = expr['data']
Eric Blake811d04f2015-05-04 09:05:10 -0600621 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600622
Eric Blake02a57ae2016-02-17 23:48:16 -0700623 # Check every branch; require at least two branches
624 if len(members) < 2:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100625 raise QAPISemError(info,
626 "Alternate '%s' should have at least two branches "
627 "in 'data'" % name)
Eric Blake811d04f2015-05-04 09:05:10 -0600628 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100629 check_name(info, "Member of alternate '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600630
Eric Blake811d04f2015-05-04 09:05:10 -0600631 # Ensure alternates have no type conflicts.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100632 check_type(info, "Member '%s' of alternate '%s'" % (key, name),
Eric Blakedd883c62015-05-04 09:05:21 -0600633 value,
634 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600635 qtype = find_alternate_member_qtype(value)
Eric Blake46534302016-02-17 23:48:17 -0700636 if not qtype:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100637 raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
638 "type '%s'" % (name, key, value))
Eric Blake811d04f2015-05-04 09:05:10 -0600639 if qtype in types_seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100640 raise QAPISemError(info, "Alternate '%s' member '%s' can't "
641 "be distinguished from member '%s'"
642 % (name, key, types_seen[qtype]))
Eric Blake811d04f2015-05-04 09:05:10 -0600643 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800644
Eric Blake437db252015-09-29 16:21:02 -0600645
Marc-André Lureau4148c292017-01-13 15:41:25 +0100646def check_enum(expr, info):
Eric Blakecf393592015-05-04 09:05:04 -0600647 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):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100652 raise QAPISemError(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):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100655 raise QAPISemError(info,
656 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600657 for member in members:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100658 check_name(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
Marc-André Lureau4148c292017-01-13 15:41:25 +0100662def check_struct(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
Marc-André Lureau4148c292017-01-13 15:41:25 +0100666 check_type(info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600667 allow_dict=True, allow_optional=True)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100668 check_type(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):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100677 raise QAPISemError(info, "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600678 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600679 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600680 if key not in required and key not in optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100681 raise QAPISemError(info, "Unknown key '%s' in %s '%s'"
682 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600683 if (key == 'gen' or key == 'success-response') and value is not False:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100684 raise QAPISemError(info,
685 "'%s' of %s '%s' should only use false value"
686 % (key, meta, name))
Eric Blakec8184082016-07-13 21:50:20 -0600687 if key == 'boxed' and value is not True:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100688 raise QAPISemError(info,
689 "'%s' of %s '%s' should only use true value"
690 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600691 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600692 if key not in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100693 raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
694 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600695
Eric Blake437db252015-09-29 16:21:02 -0600696
Markus Armbruster4d076d62015-06-10 08:55:21 +0200697def check_exprs(exprs):
698 global all_names
699
700 # Learn the types and check for valid expression keys
701 for builtin in builtin_types.keys():
702 all_names[builtin] = 'built-in'
703 for expr_elem in exprs:
704 expr = expr_elem['expr']
705 info = expr_elem['info']
Eric Blake437db252015-09-29 16:21:02 -0600706 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100707 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200708 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600709 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200710 check_keys(expr_elem, 'union', ['data'],
711 ['base', 'discriminator'])
712 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600713 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200714 check_keys(expr_elem, 'alternate', ['data'])
715 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600716 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200717 check_keys(expr_elem, 'struct', ['data'], ['base'])
718 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600719 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200720 check_keys(expr_elem, 'command', [],
Eric Blakec8184082016-07-13 21:50:20 -0600721 ['data', 'returns', 'gen', 'success-response', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200722 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600723 elif 'event' in expr:
Eric Blakec8184082016-07-13 21:50:20 -0600724 check_keys(expr_elem, 'event', [], ['data', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200725 add_name(expr['event'], info, 'event')
726 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100727 raise QAPISemError(expr_elem['info'],
728 "Expression is missing metatype")
Markus Armbruster4d076d62015-06-10 08:55:21 +0200729
730 # Try again for hidden UnionKind enum
731 for expr_elem in exprs:
732 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600733 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200734 if not discriminator_find_enum_define(expr):
735 add_enum('%sKind' % expr['union'], expr_elem['info'],
736 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600737 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200738 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
739 implicit=True)
740
741 # Validate that exprs make sense
742 for expr_elem in exprs:
743 expr = expr_elem['expr']
744 info = expr_elem['info']
745
Eric Blake437db252015-09-29 16:21:02 -0600746 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200747 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600748 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200749 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600750 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200751 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600752 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200753 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600754 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200755 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600756 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200757 check_event(expr, info)
758 else:
759 assert False, 'unexpected meta type'
760
Markus Armbrusterac882192015-09-16 13:06:05 +0200761 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600762
Markus Armbrusterac882192015-09-16 13:06:05 +0200763
764#
765# Schema compiler frontend
766#
767
768class QAPISchemaEntity(object):
769 def __init__(self, name, info):
770 assert isinstance(name, str)
771 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -0600772 # For explicitly defined entities, info points to the (explicit)
773 # definition. For builtins (and their arrays), info is None.
774 # For implicitly defined entities, info points to a place that
775 # triggered the implicit definition (there may be more than one
776 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +0200777 self.info = info
778
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200779 def c_name(self):
780 return c_name(self.name)
781
Markus Armbrusterac882192015-09-16 13:06:05 +0200782 def check(self, schema):
783 pass
784
Eric Blake49823c42015-10-12 22:22:27 -0600785 def is_implicit(self):
786 return not self.info
787
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200788 def visit(self, visitor):
789 pass
790
791
792class QAPISchemaVisitor(object):
793 def visit_begin(self, schema):
794 pass
795
796 def visit_end(self):
797 pass
798
Eric Blake25a0d9c2015-10-12 22:22:21 -0600799 def visit_needed(self, entity):
800 # Default to visiting everything
801 return True
802
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200803 def visit_builtin_type(self, name, info, json_type):
804 pass
805
806 def visit_enum_type(self, name, info, values, prefix):
807 pass
808
809 def visit_array_type(self, name, info, element_type):
810 pass
811
812 def visit_object_type(self, name, info, base, members, variants):
813 pass
814
Markus Armbruster39a18152015-09-16 13:06:28 +0200815 def visit_object_type_flat(self, name, info, members, variants):
816 pass
817
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200818 def visit_alternate_type(self, name, info, variants):
819 pass
820
821 def visit_command(self, name, info, arg_type, ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -0600822 gen, success_response, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200823 pass
824
Eric Blake48825ca2016-07-13 21:50:19 -0600825 def visit_event(self, name, info, arg_type, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200826 pass
827
Markus Armbrusterac882192015-09-16 13:06:05 +0200828
829class QAPISchemaType(QAPISchemaEntity):
Eric Blake4040d992016-03-17 16:48:28 -0600830 # Return the C type for common use.
831 # For the types we commonly box, this is a pointer type.
832 def c_type(self):
833 pass
834
835 # Return the C type to be used in a parameter list.
836 def c_param_type(self):
837 return self.c_type()
838
839 # Return the C type to be used where we suppress boxing.
840 def c_unboxed_type(self):
841 return self.c_type()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200842
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200843 def json_type(self):
844 pass
845
846 def alternate_qtype(self):
847 json2qtype = {
848 'string': 'QTYPE_QSTRING',
849 'number': 'QTYPE_QFLOAT',
850 'int': 'QTYPE_QINT',
851 'boolean': 'QTYPE_QBOOL',
852 'object': 'QTYPE_QDICT'
853 }
854 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +0200855
856
857class QAPISchemaBuiltinType(QAPISchemaType):
Eric Blake861877a2016-03-17 16:48:36 -0600858 def __init__(self, name, json_type, c_type):
Markus Armbrusterac882192015-09-16 13:06:05 +0200859 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200860 assert not c_type or isinstance(c_type, str)
861 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
862 'value')
863 self._json_type_name = json_type
864 self._c_type_name = c_type
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200865
866 def c_name(self):
867 return self.name
868
Eric Blake4040d992016-03-17 16:48:28 -0600869 def c_type(self):
870 return self._c_type_name
871
872 def c_param_type(self):
873 if self.name == 'str':
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200874 return 'const ' + self._c_type_name
875 return self._c_type_name
876
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200877 def json_type(self):
878 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +0200879
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200880 def visit(self, visitor):
881 visitor.visit_builtin_type(self.name, self.info, self.json_type())
882
Markus Armbrusterac882192015-09-16 13:06:05 +0200883
884class QAPISchemaEnumType(QAPISchemaType):
885 def __init__(self, name, info, values, prefix):
886 QAPISchemaType.__init__(self, name, info)
887 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -0700888 assert isinstance(v, QAPISchemaMember)
889 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200890 assert prefix is None or isinstance(prefix, str)
891 self.values = values
892 self.prefix = prefix
893
894 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -0700895 seen = {}
896 for v in self.values:
897 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200898
Eric Blake99df5282015-10-12 22:22:32 -0600899 def is_implicit(self):
900 # See QAPISchema._make_implicit_enum_type()
Eric Blake8712fa52015-10-26 16:34:41 -0600901 return self.name.endswith('Kind')
Eric Blake99df5282015-10-12 22:22:32 -0600902
Eric Blake4040d992016-03-17 16:48:28 -0600903 def c_type(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200904 return c_name(self.name)
905
Eric Blake93bda4d2015-12-01 22:20:55 -0700906 def member_names(self):
907 return [v.name for v in self.values]
908
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200909 def json_type(self):
910 return 'string'
911
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200912 def visit(self, visitor):
913 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -0700914 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200915
Markus Armbrusterac882192015-09-16 13:06:05 +0200916
917class QAPISchemaArrayType(QAPISchemaType):
918 def __init__(self, name, info, element_type):
919 QAPISchemaType.__init__(self, name, info)
920 assert isinstance(element_type, str)
921 self._element_type_name = element_type
922 self.element_type = None
923
924 def check(self, schema):
925 self.element_type = schema.lookup_type(self._element_type_name)
926 assert self.element_type
927
Eric Blake99df5282015-10-12 22:22:32 -0600928 def is_implicit(self):
929 return True
930
Eric Blake4040d992016-03-17 16:48:28 -0600931 def c_type(self):
932 return c_name(self.name) + pointer_suffix
933
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200934 def json_type(self):
935 return 'array'
936
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200937 def visit(self, visitor):
938 visitor.visit_array_type(self.name, self.info, self.element_type)
939
Markus Armbrusterac882192015-09-16 13:06:05 +0200940
941class QAPISchemaObjectType(QAPISchemaType):
942 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -0700943 # struct has local_members, optional base, and no variants
944 # flat union has base, variants, and no local_members
945 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +0200946 QAPISchemaType.__init__(self, name, info)
947 assert base is None or isinstance(base, str)
948 for m in local_members:
949 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -0700950 m.set_owner(name)
951 if variants is not None:
952 assert isinstance(variants, QAPISchemaObjectTypeVariants)
953 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200954 self._base_name = base
955 self.base = None
956 self.local_members = local_members
957 self.variants = variants
958 self.members = None
959
960 def check(self, schema):
Eric Blakebac54292015-12-01 22:20:59 -0700961 if self.members is False: # check for cycles
Marc-André Lureau4148c292017-01-13 15:41:25 +0100962 raise QAPISemError(self.info,
963 "Object %s contains itself" % self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200964 if self.members:
965 return
966 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -0700967 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +0200968 if self._base_name:
969 self.base = schema.lookup_type(self._base_name)
970 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +0200971 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700972 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200973 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -0700974 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700975 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700976 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +0200977 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -0700978 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700979 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -0700980 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200981
Eric Blake14f00c62016-03-03 09:16:43 -0700982 # Check that the members of this type do not cause duplicate JSON members,
Eric Blake27b60ab2015-11-18 01:52:51 -0700983 # and update seen to track the members seen so far. Report any errors
984 # on behalf of info, which is not necessarily self.info
985 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -0700986 assert not self.variants # not implemented
987 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -0700988 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -0700989
Eric Blake99df5282015-10-12 22:22:32 -0600990 def is_implicit(self):
Eric Blake75996972016-03-17 16:48:29 -0600991 # See QAPISchema._make_implicit_object_type(), as well as
992 # _def_predefineds()
993 return self.name.startswith('q_')
Eric Blake99df5282015-10-12 22:22:32 -0600994
Eric Blakeb6167702016-07-13 21:50:16 -0600995 def is_empty(self):
996 assert self.members is not None
997 return not self.members and not self.variants
998
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200999 def c_name(self):
Eric Blakecd50a252016-07-13 21:50:14 -06001000 assert self.name != 'q_empty'
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001001 return QAPISchemaType.c_name(self)
1002
Eric Blake4040d992016-03-17 16:48:28 -06001003 def c_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001004 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -07001005 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001006
Eric Blake4040d992016-03-17 16:48:28 -06001007 def c_unboxed_type(self):
Eric Blake4040d992016-03-17 16:48:28 -06001008 return c_name(self.name)
1009
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001010 def json_type(self):
1011 return 'object'
1012
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001013 def visit(self, visitor):
1014 visitor.visit_object_type(self.name, self.info,
1015 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001016 visitor.visit_object_type_flat(self.name, self.info,
1017 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001018
Markus Armbrusterac882192015-09-16 13:06:05 +02001019
Eric Blaked44f9ac2015-12-01 22:20:54 -07001020class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001021 role = 'member'
1022
Eric Blaked44f9ac2015-12-01 22:20:54 -07001023 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001024 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001025 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001026 self.owner = None
1027
1028 def set_owner(self, name):
1029 assert not self.owner
1030 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001031
Eric Blake27b60ab2015-11-18 01:52:51 -07001032 def check_clash(self, info, seen):
1033 cname = c_name(self.name)
Eric Blake893e1f22015-12-01 22:20:57 -07001034 if cname.lower() != cname and self.owner not in case_whitelist:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001035 raise QAPISemError(info,
1036 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001037 if cname in seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001038 raise QAPISemError(info, "%s collides with %s" %
1039 (self.describe(), seen[cname].describe()))
Eric Blake27b60ab2015-11-18 01:52:51 -07001040 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001041
Eric Blake88d4ef82015-11-18 01:52:50 -07001042 def _pretty_owner(self):
1043 owner = self.owner
Eric Blake75996972016-03-17 16:48:29 -06001044 if owner.startswith('q_obj_'):
Eric Blake88d4ef82015-11-18 01:52:50 -07001045 # See QAPISchema._make_implicit_object_type() - reverse the
1046 # mapping there to create a nice human-readable description
Eric Blake75996972016-03-17 16:48:29 -06001047 owner = owner[6:]
Eric Blake88d4ef82015-11-18 01:52:50 -07001048 if owner.endswith('-arg'):
1049 return '(parameter of %s)' % owner[:-4]
Eric Blakeac4338f2016-03-17 16:48:39 -06001050 elif owner.endswith('-base'):
1051 return '(base of %s)' % owner[:-5]
Eric Blake88d4ef82015-11-18 01:52:50 -07001052 else:
1053 assert owner.endswith('-wrapper')
1054 # Unreachable and not implemented
1055 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001056 if owner.endswith('Kind'):
1057 # See QAPISchema._make_implicit_enum_type()
1058 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001059 return '(%s of %s)' % (self.role, owner)
1060
1061 def describe(self):
1062 return "'%s' %s" % (self.name, self._pretty_owner())
1063
Markus Armbrusterac882192015-09-16 13:06:05 +02001064
Eric Blaked44f9ac2015-12-01 22:20:54 -07001065class QAPISchemaObjectTypeMember(QAPISchemaMember):
1066 def __init__(self, name, typ, optional):
1067 QAPISchemaMember.__init__(self, name)
1068 assert isinstance(typ, str)
1069 assert isinstance(optional, bool)
1070 self._type_name = typ
1071 self.type = None
1072 self.optional = optional
1073
1074 def check(self, schema):
1075 assert self.owner
1076 self.type = schema.lookup_type(self._type_name)
1077 assert self.type
1078
1079
Markus Armbrusterac882192015-09-16 13:06:05 +02001080class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001081 def __init__(self, tag_name, tag_member, variants):
1082 # Flat unions pass tag_name but not tag_member.
1083 # Simple unions and alternates pass tag_member but not tag_name.
1084 # After check(), tag_member is always set, and tag_name remains
1085 # a reliable witness of being used by a flat union.
1086 assert bool(tag_member) != bool(tag_name)
1087 assert (isinstance(tag_name, str) or
1088 isinstance(tag_member, QAPISchemaObjectTypeMember))
Eric Blake02a57ae2016-02-17 23:48:16 -07001089 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001090 for v in variants:
1091 assert isinstance(v, QAPISchemaObjectTypeVariant)
Eric Blakeda9cb192016-07-13 21:50:15 -06001092 self._tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001093 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001094 self.variants = variants
1095
Eric Blake88d4ef82015-11-18 01:52:50 -07001096 def set_owner(self, name):
1097 for v in self.variants:
1098 v.set_owner(name)
1099
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001100 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001101 if not self.tag_member: # flat union
Eric Blakeda9cb192016-07-13 21:50:15 -06001102 self.tag_member = seen[c_name(self._tag_name)]
1103 assert self._tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001104 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1105 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001106 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001107 # Union names must match enum values; alternate names are
1108 # checked separately. Use 'seen' to tell the two apart.
1109 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001110 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001111 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001112 v.type.check(schema)
1113
Eric Blake27b60ab2015-11-18 01:52:51 -07001114 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001115 for v in self.variants:
1116 # Reset seen map for each variant, since qapi names from one
1117 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001118 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001119 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001120
Eric Blake437db252015-09-29 16:21:02 -06001121
Markus Armbrusterac882192015-09-16 13:06:05 +02001122class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001123 role = 'branch'
1124
Markus Armbrusterac882192015-09-16 13:06:05 +02001125 def __init__(self, name, typ):
1126 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1127
Markus Armbrusterac882192015-09-16 13:06:05 +02001128
1129class QAPISchemaAlternateType(QAPISchemaType):
1130 def __init__(self, name, info, variants):
1131 QAPISchemaType.__init__(self, name, info)
1132 assert isinstance(variants, QAPISchemaObjectTypeVariants)
Eric Blakeda9cb192016-07-13 21:50:15 -06001133 assert variants.tag_member
Eric Blake88d4ef82015-11-18 01:52:50 -07001134 variants.set_owner(name)
1135 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001136 self.variants = variants
1137
1138 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001139 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001140 # Not calling self.variants.check_clash(), because there's nothing
1141 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001142 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001143 # Alternate branch names have no relation to the tag enum values;
1144 # so we have to check for potential name collisions ourselves.
1145 seen = {}
1146 for v in self.variants.variants:
1147 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001148
Eric Blake4040d992016-03-17 16:48:28 -06001149 def c_type(self):
1150 return c_name(self.name) + pointer_suffix
1151
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001152 def json_type(self):
1153 return 'value'
1154
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001155 def visit(self, visitor):
1156 visitor.visit_alternate_type(self.name, self.info, self.variants)
1157
Eric Blakec8184082016-07-13 21:50:20 -06001158 def is_empty(self):
1159 return False
1160
Markus Armbrusterac882192015-09-16 13:06:05 +02001161
1162class QAPISchemaCommand(QAPISchemaEntity):
Eric Blake48825ca2016-07-13 21:50:19 -06001163 def __init__(self, name, info, arg_type, ret_type, gen, success_response,
1164 boxed):
Markus Armbrusterac882192015-09-16 13:06:05 +02001165 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
Eric Blake48825ca2016-07-13 21:50:19 -06001174 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001175
1176 def check(self, schema):
1177 if self._arg_type_name:
1178 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001179 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1180 isinstance(self.arg_type, QAPISchemaAlternateType))
1181 self.arg_type.check(schema)
1182 if self.boxed:
1183 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001184 raise QAPISemError(self.info,
1185 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001186 else:
1187 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1188 assert not self.arg_type.variants
1189 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001190 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001191 if self._ret_type_name:
1192 self.ret_type = schema.lookup_type(self._ret_type_name)
1193 assert isinstance(self.ret_type, QAPISchemaType)
1194
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001195 def visit(self, visitor):
1196 visitor.visit_command(self.name, self.info,
1197 self.arg_type, self.ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001198 self.gen, self.success_response, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001199
Markus Armbrusterac882192015-09-16 13:06:05 +02001200
1201class QAPISchemaEvent(QAPISchemaEntity):
Eric Blake48825ca2016-07-13 21:50:19 -06001202 def __init__(self, name, info, arg_type, boxed):
Markus Armbrusterac882192015-09-16 13:06:05 +02001203 QAPISchemaEntity.__init__(self, name, info)
1204 assert not arg_type or isinstance(arg_type, str)
1205 self._arg_type_name = arg_type
1206 self.arg_type = None
Eric Blake48825ca2016-07-13 21:50:19 -06001207 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001208
1209 def check(self, schema):
1210 if self._arg_type_name:
1211 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001212 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1213 isinstance(self.arg_type, QAPISchemaAlternateType))
1214 self.arg_type.check(schema)
1215 if self.boxed:
1216 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001217 raise QAPISemError(self.info,
1218 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001219 else:
1220 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1221 assert not self.arg_type.variants
1222 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001223 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001224
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001225 def visit(self, visitor):
Eric Blake48825ca2016-07-13 21:50:19 -06001226 visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001227
Markus Armbrusterac882192015-09-16 13:06:05 +02001228
1229class QAPISchema(object):
1230 def __init__(self, fname):
1231 try:
1232 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
Eric Blake7618b912015-10-12 22:22:22 -06001233 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001234 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001235 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001236 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001237 self._def_exprs()
1238 self.check()
Marc-André Lureau4148c292017-01-13 15:41:25 +01001239 except QAPIError as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001240 print >>sys.stderr, err
1241 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001242
Markus Armbrusterac882192015-09-16 13:06:05 +02001243 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001244 # Only the predefined types are allowed to not have info
1245 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001246 assert ent.name not in self._entity_dict
1247 self._entity_dict[ent.name] = ent
1248
1249 def lookup_entity(self, name, typ=None):
1250 ent = self._entity_dict.get(name)
1251 if typ and not isinstance(ent, typ):
1252 return None
1253 return ent
1254
1255 def lookup_type(self, name):
1256 return self.lookup_entity(name, QAPISchemaType)
1257
Eric Blake861877a2016-03-17 16:48:36 -06001258 def _def_builtin_type(self, name, json_type, c_type):
1259 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001260 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1261 # qapi-types.h from a single .c, all arrays of builtins must be
1262 # declared in the first file whether or not they are used. Nicer
1263 # would be to use lazy instantiation, while figuring out how to
1264 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001265 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001266
1267 def _def_predefineds(self):
Eric Blake861877a2016-03-17 16:48:36 -06001268 for t in [('str', 'string', 'char' + pointer_suffix),
1269 ('number', 'number', 'double'),
1270 ('int', 'int', 'int64_t'),
1271 ('int8', 'int', 'int8_t'),
1272 ('int16', 'int', 'int16_t'),
1273 ('int32', 'int', 'int32_t'),
1274 ('int64', 'int', 'int64_t'),
1275 ('uint8', 'int', 'uint8_t'),
1276 ('uint16', 'int', 'uint16_t'),
1277 ('uint32', 'int', 'uint32_t'),
1278 ('uint64', 'int', 'uint64_t'),
1279 ('size', 'int', 'uint64_t'),
1280 ('bool', 'boolean', 'bool'),
1281 ('any', 'value', 'QObject' + pointer_suffix)]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001282 self._def_builtin_type(*t)
Eric Blake75996972016-03-17 16:48:29 -06001283 self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1284 None, [], None)
Markus Armbruster39a18152015-09-16 13:06:28 +02001285 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001286 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1287 'qstring', 'qdict', 'qlist',
1288 'qfloat', 'qbool'])
1289 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001290 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001291
Eric Blake93bda4d2015-12-01 22:20:55 -07001292 def _make_enum_members(self, values):
1293 return [QAPISchemaMember(v) for v in values]
1294
Eric Blake99df5282015-10-12 22:22:32 -06001295 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001296 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001297 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001298 self._def_entity(QAPISchemaEnumType(
1299 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001300 return name
1301
Eric Blake99df5282015-10-12 22:22:32 -06001302 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001303 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001304 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001305 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001306 return name
1307
Eric Blake99df5282015-10-12 22:22:32 -06001308 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001309 if not members:
1310 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001311 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake75996972016-03-17 16:48:29 -06001312 name = 'q_obj_%s-%s' % (name, role)
Markus Armbrusterac882192015-09-16 13:06:05 +02001313 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001314 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001315 members, None))
1316 return name
1317
1318 def _def_enum_type(self, expr, info):
1319 name = expr['enum']
1320 data = expr['data']
1321 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001322 self._def_entity(QAPISchemaEnumType(
1323 name, info, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001324
Eric Blake99df5282015-10-12 22:22:32 -06001325 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001326 optional = False
1327 if name.startswith('*'):
1328 name = name[1:]
1329 optional = True
1330 if isinstance(typ, list):
1331 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001332 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001333 return QAPISchemaObjectTypeMember(name, typ, optional)
1334
Eric Blake99df5282015-10-12 22:22:32 -06001335 def _make_members(self, data, info):
1336 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001337 for (key, value) in data.iteritems()]
1338
1339 def _def_struct_type(self, expr, info):
1340 name = expr['struct']
1341 base = expr.get('base')
1342 data = expr['data']
1343 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001344 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001345 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001346
1347 def _make_variant(self, case, typ):
1348 return QAPISchemaObjectTypeVariant(case, typ)
1349
Eric Blake99df5282015-10-12 22:22:32 -06001350 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001351 if isinstance(typ, list):
1352 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001353 typ = self._make_array_type(typ[0], info)
1354 typ = self._make_implicit_object_type(
1355 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001356 return QAPISchemaObjectTypeVariant(case, typ)
1357
Markus Armbrusterac882192015-09-16 13:06:05 +02001358 def _def_union_type(self, expr, info):
1359 name = expr['union']
1360 data = expr['data']
1361 base = expr.get('base')
1362 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001363 tag_member = None
Eric Blakeac4338f2016-03-17 16:48:39 -06001364 if isinstance(base, dict):
1365 base = (self._make_implicit_object_type(
1366 name, info, 'base', self._make_members(base, info)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001367 if tag_name:
1368 variants = [self._make_variant(key, value)
1369 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001370 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001371 else:
Eric Blake99df5282015-10-12 22:22:32 -06001372 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001373 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001374 typ = self._make_implicit_enum_type(name, info,
1375 [v.name for v in variants])
1376 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001377 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001378 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001379 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001380 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001381 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001382 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001383
1384 def _def_alternate_type(self, expr, info):
1385 name = expr['alternate']
1386 data = expr['data']
1387 variants = [self._make_variant(key, value)
1388 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001389 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001390 self._def_entity(
1391 QAPISchemaAlternateType(name, info,
1392 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001393 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001394 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001395
1396 def _def_command(self, expr, info):
1397 name = expr['command']
1398 data = expr.get('data')
1399 rets = expr.get('returns')
1400 gen = expr.get('gen', True)
1401 success_response = expr.get('success-response', True)
Eric Blake48825ca2016-07-13 21:50:19 -06001402 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001403 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001404 data = self._make_implicit_object_type(
1405 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001406 if isinstance(rets, list):
1407 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001408 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001409 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
Eric Blake48825ca2016-07-13 21:50:19 -06001410 success_response, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001411
1412 def _def_event(self, expr, info):
1413 name = expr['event']
1414 data = expr.get('data')
Eric Blake48825ca2016-07-13 21:50:19 -06001415 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001416 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001417 data = self._make_implicit_object_type(
1418 name, info, 'arg', self._make_members(data, info))
Eric Blake48825ca2016-07-13 21:50:19 -06001419 self._def_entity(QAPISchemaEvent(name, info, data, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001420
1421 def _def_exprs(self):
1422 for expr_elem in self.exprs:
1423 expr = expr_elem['expr']
1424 info = expr_elem['info']
1425 if 'enum' in expr:
1426 self._def_enum_type(expr, info)
1427 elif 'struct' in expr:
1428 self._def_struct_type(expr, info)
1429 elif 'union' in expr:
1430 self._def_union_type(expr, info)
1431 elif 'alternate' in expr:
1432 self._def_alternate_type(expr, info)
1433 elif 'command' in expr:
1434 self._def_command(expr, info)
1435 elif 'event' in expr:
1436 self._def_event(expr, info)
1437 else:
1438 assert False
1439
1440 def check(self):
1441 for ent in self._entity_dict.values():
1442 ent.check(self)
1443
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001444 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001445 visitor.visit_begin(self)
1446 for (name, entity) in sorted(self._entity_dict.items()):
1447 if visitor.visit_needed(entity):
1448 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001449 visitor.visit_end()
1450
Markus Armbruster2caba362013-07-27 17:41:56 +02001451
Markus Armbruster00e4b282015-06-10 10:04:36 +02001452#
1453# Code generation helpers
1454#
1455
Michael Roth0f923be2011-07-19 14:50:39 -05001456def camel_case(name):
1457 new_name = ''
1458 first = True
1459 for ch in name:
1460 if ch in ['_', '-']:
1461 first = True
1462 elif first:
1463 new_name += ch.upper()
1464 first = False
1465 else:
1466 new_name += ch.lower()
1467 return new_name
1468
Eric Blake437db252015-09-29 16:21:02 -06001469
Markus Armbruster849bc532015-05-14 06:50:53 -06001470# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1471# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1472# ENUM24_Name -> ENUM24_NAME
1473def camel_to_upper(value):
1474 c_fun_str = c_name(value, False)
1475 if value.isupper():
1476 return c_fun_str
1477
1478 new_name = ''
1479 l = len(c_fun_str)
1480 for i in range(l):
1481 c = c_fun_str[i]
1482 # When c is upper and no "_" appears before, do more checks
1483 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001484 if i < l - 1 and c_fun_str[i + 1].islower():
1485 new_name += '_'
1486 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001487 new_name += '_'
1488 new_name += c
1489 return new_name.lstrip('_').upper()
1490
Eric Blake437db252015-09-29 16:21:02 -06001491
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001492def c_enum_const(type_name, const_name, prefix=None):
1493 if prefix is not None:
1494 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001495 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001496
Eric Blake18df5152015-05-14 06:50:48 -06001497c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001498
Eric Blake437db252015-09-29 16:21:02 -06001499
Eric Blakec6405b52015-05-14 06:50:55 -06001500# Map @name to a valid C identifier.
1501# If @protect, avoid returning certain ticklish identifiers (like
1502# C keywords) by prepending "q_".
1503#
1504# Used for converting 'name' from a 'name':'type' qapi definition
1505# into a generated struct member, as well as converting type names
1506# into substrings of a generated C function name.
1507# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1508# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001509def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001510 # ANSI X3J11/88-090, 3.1.1
1511 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001512 'default', 'do', 'double', 'else', 'enum', 'extern',
1513 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1514 'return', 'short', 'signed', 'sizeof', 'static',
1515 'struct', 'switch', 'typedef', 'union', 'unsigned',
1516 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001517 # ISO/IEC 9899:1999, 6.4.1
1518 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1519 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001520 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1521 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001522 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1523 # excluding _.*
1524 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001525 # C++ ISO/IEC 14882:2003 2.11
1526 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1527 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1528 'namespace', 'new', 'operator', 'private', 'protected',
1529 'public', 'reinterpret_cast', 'static_cast', 'template',
1530 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1531 'using', 'virtual', 'wchar_t',
1532 # alternative representations
1533 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1534 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001535 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001536 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001537 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001538 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1539 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001540 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001541 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001542
Amos Kong05dfb262014-06-10 19:25:53 +08001543eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001544pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001545
Eric Blake437db252015-09-29 16:21:02 -06001546
Michael Roth0f923be2011-07-19 14:50:39 -05001547def genindent(count):
1548 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001549 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001550 ret += " "
1551 return ret
1552
1553indent_level = 0
1554
Eric Blake437db252015-09-29 16:21:02 -06001555
Michael Roth0f923be2011-07-19 14:50:39 -05001556def push_indent(indent_amount=4):
1557 global indent_level
1558 indent_level += indent_amount
1559
Eric Blake437db252015-09-29 16:21:02 -06001560
Michael Roth0f923be2011-07-19 14:50:39 -05001561def pop_indent(indent_amount=4):
1562 global indent_level
1563 indent_level -= indent_amount
1564
Eric Blake437db252015-09-29 16:21:02 -06001565
Markus Armbruster77e703b2015-06-24 19:27:32 +02001566# Generate @code with @kwds interpolated.
1567# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001568def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001569 raw = code % kwds
1570 if indent_level:
1571 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001572 # re.subn() lacks flags support before Python 2.7, use re.compile()
1573 raw = re.subn(re.compile("^.", re.MULTILINE),
1574 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001575 raw = raw[0]
1576 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001577
Eric Blake437db252015-09-29 16:21:02 -06001578
Michael Roth0f923be2011-07-19 14:50:39 -05001579def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001580 if code[0] == '\n':
1581 code = code[1:]
1582 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001583
Michael Roth0f923be2011-07-19 14:50:39 -05001584
1585def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001586 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001587
Eric Blake437db252015-09-29 16:21:02 -06001588
Michael Rothc0afa9c2013-05-10 17:46:00 -05001589def guardstart(name):
1590 return mcgen('''
1591
1592#ifndef %(name)s
1593#define %(name)s
1594
1595''',
1596 name=guardname(name))
1597
Eric Blake437db252015-09-29 16:21:02 -06001598
Michael Rothc0afa9c2013-05-10 17:46:00 -05001599def guardend(name):
1600 return mcgen('''
1601
1602#endif /* %(name)s */
1603
1604''',
1605 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001606
Eric Blake437db252015-09-29 16:21:02 -06001607
Markus Armbrustere98859a2015-09-16 13:06:16 +02001608def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001609 ret = mcgen('''
1610
Markus Armbrustere98859a2015-09-16 13:06:16 +02001611const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001612''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001613 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001614 for value in values:
1615 index = c_enum_const(name, value, prefix)
1616 ret += mcgen('''
1617 [%(index)s] = "%(value)s",
1618''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001619 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001620
Eric Blake7fb1cf12015-11-18 01:52:57 -07001621 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001622 ret += mcgen('''
1623 [%(max_index)s] = NULL,
1624};
1625''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001626 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001627 return ret
1628
Eric Blake437db252015-09-29 16:21:02 -06001629
Markus Armbrustere98859a2015-09-16 13:06:16 +02001630def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001631 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001632 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001633
1634 ret = mcgen('''
1635
1636typedef enum %(c_name)s {
1637''',
1638 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001639
1640 i = 0
1641 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001642 ret += mcgen('''
1643 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001644''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001645 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001646 i=i)
1647 i += 1
1648
Markus Armbrustere98859a2015-09-16 13:06:16 +02001649 ret += mcgen('''
1650} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001651''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001652 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001653
Markus Armbrustere98859a2015-09-16 13:06:16 +02001654 ret += mcgen('''
1655
1656extern const char *const %(c_name)s_lookup[];
1657''',
1658 c_name=c_name(name))
1659 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001660
Eric Blake437db252015-09-29 16:21:02 -06001661
Eric Blake48825ca2016-07-13 21:50:19 -06001662def gen_params(arg_type, boxed, extra):
Markus Armbruster03b43672015-09-16 13:06:20 +02001663 if not arg_type:
Eric Blakec8184082016-07-13 21:50:20 -06001664 assert not boxed
Markus Armbruster03b43672015-09-16 13:06:20 +02001665 return extra
Markus Armbruster03b43672015-09-16 13:06:20 +02001666 ret = ''
1667 sep = ''
Eric Blake48825ca2016-07-13 21:50:19 -06001668 if boxed:
Eric Blakec8184082016-07-13 21:50:20 -06001669 ret += '%s arg' % arg_type.c_param_type()
1670 sep = ', '
Eric Blake48825ca2016-07-13 21:50:19 -06001671 else:
1672 assert not arg_type.variants
1673 for memb in arg_type.members:
1674 ret += sep
1675 sep = ', '
1676 if memb.optional:
1677 ret += 'bool has_%s, ' % c_name(memb.name)
1678 ret += '%s %s' % (memb.type.c_param_type(),
1679 c_name(memb.name))
Markus Armbruster03b43672015-09-16 13:06:20 +02001680 if extra:
1681 ret += sep + extra
1682 return ret
1683
Eric Blake1f353342015-09-29 16:21:13 -06001684
Markus Armbruster00e4b282015-06-10 10:04:36 +02001685#
1686# Common command line parsing
1687#
1688
Eric Blake437db252015-09-29 16:21:02 -06001689
1690def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001691
1692 try:
1693 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001694 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001695 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001696 "output-dir="] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001697 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001698 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001699 sys.exit(1)
1700
1701 output_dir = ""
1702 prefix = ""
1703 do_c = False
1704 do_h = False
1705 extra_opts = []
1706
1707 for oa in opts:
1708 o, a = oa
1709 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001710 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1711 if match.end() != len(a):
1712 print >>sys.stderr, \
1713 "%s: 'funny character '%s' in argument of --prefix" \
1714 % (sys.argv[0], a[match.end()])
1715 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001716 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001717 elif o in ("-o", "--output-dir"):
1718 output_dir = a + "/"
1719 elif o in ("-c", "--source"):
1720 do_c = True
1721 elif o in ("-h", "--header"):
1722 do_h = True
1723 else:
1724 extra_opts.append(oa)
1725
1726 if not do_c and not do_h:
1727 do_c = True
1728 do_h = True
1729
Markus Armbruster16d80f62015-04-02 13:32:16 +02001730 if len(args) != 1:
1731 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001732 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001733 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001734
Markus Armbruster54414042015-06-09 16:22:45 +02001735 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001736
Markus Armbruster00e4b282015-06-10 10:04:36 +02001737#
1738# Generate output files with boilerplate
1739#
1740
Eric Blake437db252015-09-29 16:21:02 -06001741
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001742def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1743 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001744 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001745 c_file = output_dir + prefix + c_file
1746 h_file = output_dir + prefix + h_file
1747
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001748 if output_dir:
1749 try:
1750 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01001751 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001752 if e.errno != errno.EEXIST:
1753 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001754
1755 def maybe_open(really, name, opt):
1756 if really:
1757 return open(name, opt)
1758 else:
1759 import StringIO
1760 return StringIO.StringIO()
1761
1762 fdef = maybe_open(do_c, c_file, 'w')
1763 fdecl = maybe_open(do_h, h_file, 'w')
1764
1765 fdef.write(mcgen('''
1766/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1767%(comment)s
1768''',
Eric Blake437db252015-09-29 16:21:02 -06001769 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001770
1771 fdecl.write(mcgen('''
1772/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1773%(comment)s
1774#ifndef %(guard)s
1775#define %(guard)s
1776
1777''',
Eric Blake437db252015-09-29 16:21:02 -06001778 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001779
1780 return (fdef, fdecl)
1781
Eric Blake437db252015-09-29 16:21:02 -06001782
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001783def close_output(fdef, fdecl):
1784 fdecl.write('''
1785#endif
1786''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001787 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001788 fdef.close()