]>
Commit | Line | Data |
---|---|---|
06d64c62 MR |
1 | # |
2 | # QAPI visitor generator | |
3 | # | |
4 | # Copyright IBM, Corp. 2011 | |
6540e9f3 | 5 | # Copyright (C) 2014-2015 Red Hat, Inc. |
06d64c62 MR |
6 | # |
7 | # Authors: | |
8 | # Anthony Liguori <aliguori@us.ibm.com> | |
9 | # Michael Roth <mdroth@linux.vnet.ibm.com> | |
297a3646 | 10 | # Markus Armbruster <armbru@redhat.com> |
06d64c62 | 11 | # |
678e48a2 MA |
12 | # This work is licensed under the terms of the GNU GPL, version 2. |
13 | # See the COPYING file in the top-level directory. | |
06d64c62 MR |
14 | |
15 | from ordereddict import OrderedDict | |
16 | from qapi import * | |
297a3646 | 17 | import re |
06d64c62 | 18 | import os |
06d64c62 MR |
19 | import errno |
20 | ||
be3c7717 MA |
21 | implicit_structs = [] |
22 | ||
23 | def generate_visit_implicit_struct(type): | |
24 | global implicit_structs | |
25 | if type in implicit_structs: | |
26 | return '' | |
27 | implicit_structs.append(type) | |
28 | return mcgen(''' | |
29 | ||
30 | static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp) | |
31 | { | |
32 | Error *err = NULL; | |
33 | ||
34 | visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err); | |
35 | if (!err) { | |
297a3646 | 36 | visit_type_%(c_type)s_fields(m, obj, errp); |
be3c7717 MA |
37 | visit_end_implicit_struct(m, &err); |
38 | } | |
39 | error_propagate(errp, err); | |
40 | } | |
41 | ''', | |
42 | c_type=type_name(type)) | |
43 | ||
a82b982e | 44 | def generate_visit_struct_fields(name, members, base = None): |
50f2bdc7 | 45 | substructs = [] |
d131c897 | 46 | ret = '' |
50f2bdc7 | 47 | |
be3c7717 MA |
48 | if base: |
49 | ret += generate_visit_implicit_struct(base) | |
50 | ||
50f2bdc7 KW |
51 | ret += mcgen(''' |
52 | ||
a82b982e | 53 | static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp) |
50f2bdc7 KW |
54 | { |
55 | Error *err = NULL; | |
56 | ''', | |
83a02706 | 57 | name=c_name(name)) |
50f2bdc7 | 58 | push_indent() |
d195325b | 59 | |
622f557f KW |
60 | if base: |
61 | ret += mcgen(''' | |
a82b982e | 62 | visit_type_implicit_%(type)s(m, &(*obj)->%(c_name)s, &err); |
297a3646 MA |
63 | if (err) { |
64 | goto out; | |
65 | } | |
622f557f | 66 | ''', |
18df515e | 67 | type=type_name(base), c_name=c_name('base')) |
622f557f | 68 | |
6b5abc7d | 69 | for argname, argentry, optional in parse_args(members): |
06d64c62 MR |
70 | if optional: |
71 | ret += mcgen(''' | |
a82b982e EB |
72 | visit_optional(m, &(*obj)->has_%(c_name)s, "%(name)s", &err); |
73 | if (!err && (*obj)->has_%(c_name)s) { | |
06d64c62 | 74 | ''', |
18df515e | 75 | c_name=c_name(argname), name=argname) |
06d64c62 MR |
76 | push_indent() |
77 | ||
6b5abc7d | 78 | ret += mcgen(''' |
a82b982e | 79 | visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err); |
06d64c62 | 80 | ''', |
18df515e | 81 | type=type_name(argentry), c_name=c_name(argname), |
6b5abc7d | 82 | name=argname) |
06d64c62 MR |
83 | |
84 | if optional: | |
85 | pop_indent() | |
86 | ret += mcgen(''' | |
87 | } | |
297a3646 MA |
88 | ''') |
89 | ret += mcgen(''' | |
90 | if (err) { | |
91 | goto out; | |
92 | } | |
d195325b PB |
93 | ''') |
94 | ||
50f2bdc7 | 95 | pop_indent() |
297a3646 MA |
96 | if re.search('^ *goto out\\;', ret, re.MULTILINE): |
97 | ret += mcgen(''' | |
50f2bdc7 | 98 | |
297a3646 MA |
99 | out: |
100 | ''') | |
101 | ret += mcgen(''' | |
50f2bdc7 KW |
102 | error_propagate(errp, err); |
103 | } | |
104 | ''') | |
d131c897 KW |
105 | return ret |
106 | ||
107 | ||
a82b982e | 108 | def generate_visit_struct_body(name, members): |
d131c897 | 109 | ret = mcgen(''' |
297a3646 MA |
110 | Error *err = NULL; |
111 | ||
83a02706 | 112 | visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err); |
297a3646 MA |
113 | if (!err) { |
114 | if (*obj) { | |
83a02706 | 115 | visit_type_%(c_name)s_fields(m, obj, errp); |
297a3646 MA |
116 | } |
117 | visit_end_struct(m, &err); | |
50f2bdc7 | 118 | } |
297a3646 | 119 | error_propagate(errp, err); |
50f2bdc7 | 120 | ''', |
83a02706 | 121 | name=name, c_name=c_name(name)) |
d195325b | 122 | |
06d64c62 MR |
123 | return ret |
124 | ||
14d36307 KW |
125 | def generate_visit_struct(expr): |
126 | ||
fd41dd4e | 127 | name = expr['struct'] |
14d36307 | 128 | members = expr['data'] |
622f557f | 129 | base = expr.get('base') |
14d36307 | 130 | |
a82b982e | 131 | ret = generate_visit_struct_fields(name, members, base) |
50f2bdc7 KW |
132 | |
133 | ret += mcgen(''' | |
06d64c62 | 134 | |
638ca8ad | 135 | void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp) |
06d64c62 | 136 | { |
06d64c62 | 137 | ''', |
83a02706 | 138 | name=c_name(name)) |
d195325b | 139 | |
a82b982e | 140 | ret += generate_visit_struct_body(name, members) |
06d64c62 MR |
141 | |
142 | ret += mcgen(''' | |
06d64c62 MR |
143 | } |
144 | ''') | |
145 | return ret | |
146 | ||
147 | def generate_visit_list(name, members): | |
148 | return mcgen(''' | |
149 | ||
638ca8ad | 150 | void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp) |
06d64c62 | 151 | { |
d195325b | 152 | Error *err = NULL; |
297a3646 | 153 | GenericList *i, **prev; |
06d64c62 | 154 | |
297a3646 MA |
155 | visit_start_list(m, name, &err); |
156 | if (err) { | |
157 | goto out; | |
158 | } | |
159 | ||
160 | for (prev = (GenericList **)obj; | |
161 | !err && (i = visit_next_list(m, prev, &err)) != NULL; | |
162 | prev = &i) { | |
163 | %(name)sList *native_i = (%(name)sList *)i; | |
164 | visit_type_%(name)s(m, &native_i->value, NULL, &err); | |
06d64c62 | 165 | } |
297a3646 MA |
166 | |
167 | error_propagate(errp, err); | |
168 | err = NULL; | |
169 | visit_end_list(m, &err); | |
170 | out: | |
171 | error_propagate(errp, err); | |
06d64c62 MR |
172 | } |
173 | ''', | |
fce384b8 | 174 | name=type_name(name)) |
06d64c62 MR |
175 | |
176 | def generate_visit_enum(name, members): | |
177 | return mcgen(''' | |
178 | ||
638ca8ad | 179 | void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp) |
06d64c62 MR |
180 | { |
181 | visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp); | |
182 | } | |
183 | ''', | |
fce384b8 | 184 | name=c_name(name)) |
06d64c62 | 185 | |
811d04fd | 186 | def generate_visit_alternate(name, members): |
69dd62df KW |
187 | ret = mcgen(''' |
188 | ||
638ca8ad | 189 | void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp) |
69dd62df KW |
190 | { |
191 | Error *err = NULL; | |
192 | ||
297a3646 MA |
193 | visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err); |
194 | if (err) { | |
195 | goto out; | |
196 | } | |
197 | visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err); | |
198 | if (err) { | |
199 | goto out_end; | |
200 | } | |
201 | switch ((*obj)->kind) { | |
69dd62df | 202 | ''', |
d1f07c86 | 203 | name=c_name(name)) |
69dd62df | 204 | |
ab916fad | 205 | # For alternate, always use the default enum type automatically generated |
d1f07c86 EB |
206 | # as name + 'Kind' |
207 | disc_type = c_name(name) + 'Kind' | |
b0b58195 | 208 | |
69dd62df | 209 | for key in members: |
b52c4b9c | 210 | assert (members[key] in builtin_types.keys() |
69dd62df | 211 | or find_struct(members[key]) |
e775ba77 | 212 | or find_union(members[key]) |
ab916fad | 213 | or find_enum(members[key])), "Invalid alternate member" |
69dd62df | 214 | |
7c81c61f | 215 | enum_full_value = c_enum_const(disc_type, key) |
69dd62df | 216 | ret += mcgen(''' |
297a3646 MA |
217 | case %(enum_full_value)s: |
218 | visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); | |
219 | break; | |
69dd62df | 220 | ''', |
b0b58195 | 221 | enum_full_value = enum_full_value, |
69dd62df | 222 | c_type = type_name(members[key]), |
18df515e | 223 | c_name = c_name(key)) |
69dd62df KW |
224 | |
225 | ret += mcgen(''' | |
297a3646 MA |
226 | default: |
227 | abort(); | |
69dd62df | 228 | } |
297a3646 MA |
229 | out_end: |
230 | error_propagate(errp, err); | |
231 | err = NULL; | |
232 | visit_end_implicit_struct(m, &err); | |
233 | out: | |
234 | error_propagate(errp, err); | |
69dd62df KW |
235 | } |
236 | ''') | |
237 | ||
238 | return ret | |
239 | ||
240 | ||
0aef92b9 KW |
241 | def generate_visit_union(expr): |
242 | ||
243 | name = expr['union'] | |
244 | members = expr['data'] | |
245 | ||
246 | base = expr.get('base') | |
50f2bdc7 | 247 | discriminator = expr.get('discriminator') |
0aef92b9 | 248 | |
bceae769 WX |
249 | enum_define = discriminator_find_enum_define(expr) |
250 | if enum_define: | |
251 | # Use the enum type as discriminator | |
252 | ret = "" | |
857af5f0 | 253 | disc_type = c_name(enum_define['enum_name']) |
bceae769 | 254 | else: |
a8d4a2e4 | 255 | # There will always be a discriminator in the C switch code, by default |
bb337290 EB |
256 | # it is an enum type generated silently |
257 | ret = generate_visit_enum(name + 'Kind', members.keys()) | |
258 | disc_type = c_name(name) + 'Kind' | |
06d64c62 | 259 | |
50f2bdc7 | 260 | if base: |
a8d4a2e4 EB |
261 | assert discriminator |
262 | base_fields = find_struct(base)['data'].copy() | |
263 | del base_fields[discriminator] | |
a82b982e | 264 | ret += generate_visit_struct_fields(name, base_fields) |
50f2bdc7 | 265 | |
be3c7717 MA |
266 | if discriminator: |
267 | for key in members: | |
268 | ret += generate_visit_implicit_struct(members[key]) | |
269 | ||
06d64c62 MR |
270 | ret += mcgen(''' |
271 | ||
638ca8ad | 272 | void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp) |
06d64c62 | 273 | { |
dc8fb6df PB |
274 | Error *err = NULL; |
275 | ||
297a3646 MA |
276 | visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); |
277 | if (err) { | |
278 | goto out; | |
279 | } | |
280 | if (*obj) { | |
06d64c62 | 281 | ''', |
bb337290 | 282 | name=c_name(name)) |
06d64c62 | 283 | |
0aef92b9 | 284 | if base: |
50f2bdc7 | 285 | ret += mcgen(''' |
468866b8 | 286 | visit_type_%(name)s_fields(m, obj, &err); |
297a3646 MA |
287 | if (err) { |
288 | goto out_obj; | |
289 | } | |
50f2bdc7 | 290 | ''', |
857af5f0 | 291 | name=c_name(name)) |
0aef92b9 | 292 | |
7b75d9d6 | 293 | if not discriminator: |
bceae769 | 294 | disc_key = "type" |
7b75d9d6 | 295 | else: |
bceae769 | 296 | disc_key = discriminator |
0aef92b9 | 297 | ret += mcgen(''' |
bceae769 | 298 | visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err); |
297a3646 MA |
299 | if (err) { |
300 | goto out_obj; | |
301 | } | |
cee2dedb MR |
302 | if (!visit_start_union(m, !!(*obj)->data, &err) || err) { |
303 | goto out_obj; | |
304 | } | |
297a3646 | 305 | switch ((*obj)->kind) { |
0aef92b9 | 306 | ''', |
bceae769 WX |
307 | disc_type = disc_type, |
308 | disc_key = disc_key) | |
0aef92b9 | 309 | |
dc8fb6df | 310 | for key in members: |
50f2bdc7 KW |
311 | if not discriminator: |
312 | fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);' | |
313 | else: | |
be3c7717 | 314 | fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);' |
50f2bdc7 | 315 | |
7c81c61f | 316 | enum_full_value = c_enum_const(disc_type, key) |
dc8fb6df | 317 | ret += mcgen(''' |
297a3646 MA |
318 | case %(enum_full_value)s: |
319 | ''' + fmt + ''' | |
320 | break; | |
dc8fb6df | 321 | ''', |
b0b58195 | 322 | enum_full_value = enum_full_value, |
c664aef5 | 323 | c_type=type_name(members[key]), |
18df515e | 324 | c_name=c_name(key)) |
dc8fb6df PB |
325 | |
326 | ret += mcgen(''' | |
297a3646 MA |
327 | default: |
328 | abort(); | |
d195325b | 329 | } |
297a3646 | 330 | out_obj: |
d195325b PB |
331 | error_propagate(errp, err); |
332 | err = NULL; | |
cee2dedb MR |
333 | visit_end_union(m, !!(*obj)->data, &err); |
334 | error_propagate(errp, err); | |
335 | err = NULL; | |
468866b8 | 336 | } |
297a3646 MA |
337 | visit_end_struct(m, &err); |
338 | out: | |
339 | error_propagate(errp, err); | |
dc8fb6df PB |
340 | } |
341 | ''') | |
342 | ||
06d64c62 MR |
343 | return ret |
344 | ||
6540e9f3 | 345 | def generate_declaration(name, members, builtin_type=False): |
7c946bc4 MR |
346 | ret = "" |
347 | if not builtin_type: | |
83a02706 | 348 | name = c_name(name) |
7c946bc4 | 349 | ret += mcgen(''' |
06d64c62 | 350 | |
638ca8ad | 351 | void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp); |
06d64c62 | 352 | ''', |
6540e9f3 | 353 | name=name) |
06d64c62 | 354 | |
6540e9f3 | 355 | ret += mcgen(''' |
638ca8ad | 356 | void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp); |
06d64c62 MR |
357 | ''', |
358 | name=name) | |
359 | ||
360 | return ret | |
361 | ||
6540e9f3 EB |
362 | def generate_enum_declaration(name, members): |
363 | ret = mcgen(''' | |
638ca8ad | 364 | void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp); |
b9c4b48d | 365 | ''', |
fce384b8 | 366 | name=c_name(name)) |
b9c4b48d AK |
367 | |
368 | return ret | |
369 | ||
6540e9f3 | 370 | def generate_decl_enum(name, members): |
06d64c62 MR |
371 | return mcgen(''' |
372 | ||
638ca8ad | 373 | void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp); |
06d64c62 | 374 | ''', |
fce384b8 | 375 | name=c_name(name)) |
06d64c62 | 376 | |
06d64c62 MR |
377 | c_file = 'qapi-visit.c' |
378 | h_file = 'qapi-visit.h' | |
7c946bc4 | 379 | do_builtins = False |
8d3bc517 | 380 | |
2114f5a9 MA |
381 | (input_file, output_dir, do_c, do_h, prefix, opts) = \ |
382 | parse_command_line("b", ["builtins"]) | |
383 | ||
06d64c62 | 384 | for o, a in opts: |
2114f5a9 | 385 | if o in ("-b", "--builtins"): |
7c946bc4 | 386 | do_builtins = True |
8d3bc517 | 387 | |
06d64c62 MR |
388 | c_file = output_dir + prefix + c_file |
389 | h_file = output_dir + prefix + h_file | |
390 | ||
391 | try: | |
392 | os.makedirs(output_dir) | |
393 | except os.error, e: | |
394 | if e.errno != errno.EEXIST: | |
395 | raise | |
396 | ||
8d3bc517 | 397 | def maybe_open(really, name, opt): |
8d3bc517 AK |
398 | if really: |
399 | return open(name, opt) | |
19bf7c87 AK |
400 | else: |
401 | import StringIO | |
402 | return StringIO.StringIO() | |
8d3bc517 AK |
403 | |
404 | fdef = maybe_open(do_c, c_file, 'w') | |
405 | fdecl = maybe_open(do_h, h_file, 'w') | |
06d64c62 MR |
406 | |
407 | fdef.write(mcgen(''' | |
408 | /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ | |
409 | ||
410 | /* | |
411 | * schema-defined QAPI visitor functions | |
412 | * | |
413 | * Copyright IBM, Corp. 2011 | |
414 | * | |
415 | * Authors: | |
416 | * Anthony Liguori <aliguori@us.ibm.com> | |
417 | * | |
418 | * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. | |
419 | * See the COPYING.LIB file in the top-level directory. | |
420 | * | |
421 | */ | |
422 | ||
79ee7df8 | 423 | #include "qemu-common.h" |
06d64c62 MR |
424 | #include "%(header)s" |
425 | ''', | |
426 | header=basename(h_file))) | |
427 | ||
428 | fdecl.write(mcgen(''' | |
429 | /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ | |
430 | ||
431 | /* | |
297a3646 | 432 | * schema-defined QAPI visitor functions |
06d64c62 MR |
433 | * |
434 | * Copyright IBM, Corp. 2011 | |
435 | * | |
436 | * Authors: | |
437 | * Anthony Liguori <aliguori@us.ibm.com> | |
438 | * | |
439 | * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. | |
440 | * See the COPYING.LIB file in the top-level directory. | |
441 | * | |
442 | */ | |
443 | ||
444 | #ifndef %(guard)s | |
445 | #define %(guard)s | |
446 | ||
7b1b5d19 | 447 | #include "qapi/visitor.h" |
06d64c62 | 448 | #include "%(prefix)sqapi-types.h" |
7c946bc4 | 449 | |
06d64c62 MR |
450 | ''', |
451 | prefix=prefix, guard=guardname(h_file))) | |
452 | ||
33aaad52 | 453 | exprs = parse_schema(input_file) |
06d64c62 | 454 | |
7c946bc4 MR |
455 | # to avoid header dependency hell, we always generate declarations |
456 | # for built-in types in our header files and simply guard them | |
457 | fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL")) | |
b52c4b9c | 458 | for typename in builtin_types.keys(): |
6540e9f3 | 459 | fdecl.write(generate_declaration(typename, None, builtin_type=True)) |
7c946bc4 MR |
460 | fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL")) |
461 | ||
462 | # ...this doesn't work for cases where we link in multiple objects that | |
463 | # have the functions defined, so we use -b option to provide control | |
464 | # over these cases | |
465 | if do_builtins: | |
b52c4b9c | 466 | for typename in builtin_types.keys(): |
7c946bc4 | 467 | fdef.write(generate_visit_list(typename, None)) |
7c946bc4 | 468 | |
06d64c62 | 469 | for expr in exprs: |
fd41dd4e | 470 | if expr.has_key('struct'): |
14d36307 | 471 | ret = generate_visit_struct(expr) |
fd41dd4e | 472 | ret += generate_visit_list(expr['struct'], expr['data']) |
06d64c62 MR |
473 | fdef.write(ret) |
474 | ||
fd41dd4e | 475 | ret = generate_declaration(expr['struct'], expr['data']) |
06d64c62 MR |
476 | fdecl.write(ret) |
477 | elif expr.has_key('union'): | |
0aef92b9 | 478 | ret = generate_visit_union(expr) |
dc8fb6df | 479 | ret += generate_visit_list(expr['union'], expr['data']) |
06d64c62 MR |
480 | fdef.write(ret) |
481 | ||
bceae769 WX |
482 | enum_define = discriminator_find_enum_define(expr) |
483 | ret = "" | |
484 | if not enum_define: | |
485 | ret = generate_decl_enum('%sKind' % expr['union'], | |
486 | expr['data'].keys()) | |
06d64c62 MR |
487 | ret += generate_declaration(expr['union'], expr['data']) |
488 | fdecl.write(ret) | |
ab916fad EB |
489 | elif expr.has_key('alternate'): |
490 | ret = generate_visit_alternate(expr['alternate'], expr['data']) | |
491 | ret += generate_visit_list(expr['alternate'], expr['data']) | |
492 | fdef.write(ret) | |
493 | ||
494 | ret = generate_decl_enum('%sKind' % expr['alternate'], | |
495 | expr['data'].keys()) | |
496 | ret += generate_declaration(expr['alternate'], expr['data']) | |
497 | fdecl.write(ret) | |
06d64c62 | 498 | elif expr.has_key('enum'): |
b9c4b48d AK |
499 | ret = generate_visit_list(expr['enum'], expr['data']) |
500 | ret += generate_visit_enum(expr['enum'], expr['data']) | |
06d64c62 MR |
501 | fdef.write(ret) |
502 | ||
503 | ret = generate_decl_enum(expr['enum'], expr['data']) | |
b9c4b48d | 504 | ret += generate_enum_declaration(expr['enum'], expr['data']) |
06d64c62 MR |
505 | fdecl.write(ret) |
506 | ||
507 | fdecl.write(''' | |
508 | #endif | |
509 | ''') | |
510 | ||
511 | fdecl.flush() | |
512 | fdecl.close() | |
513 | ||
514 | fdef.flush() | |
515 | fdef.close() |