]>
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 | |
be3c7717 MA |
19 | implicit_structs = [] |
20 | ||
21 | def generate_visit_implicit_struct(type): | |
22 | global implicit_structs | |
23 | if type in implicit_structs: | |
24 | return '' | |
25 | implicit_structs.append(type) | |
26 | return mcgen(''' | |
27 | ||
28 | static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp) | |
29 | { | |
30 | Error *err = NULL; | |
31 | ||
32 | visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err); | |
33 | if (!err) { | |
297a3646 | 34 | visit_type_%(c_type)s_fields(m, obj, errp); |
be3c7717 MA |
35 | visit_end_implicit_struct(m, &err); |
36 | } | |
37 | error_propagate(errp, err); | |
38 | } | |
39 | ''', | |
40 | c_type=type_name(type)) | |
41 | ||
a82b982e | 42 | def generate_visit_struct_fields(name, members, base = None): |
d131c897 | 43 | ret = '' |
50f2bdc7 | 44 | |
be3c7717 MA |
45 | if base: |
46 | ret += generate_visit_implicit_struct(base) | |
47 | ||
50f2bdc7 KW |
48 | ret += mcgen(''' |
49 | ||
a82b982e | 50 | static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp) |
50f2bdc7 KW |
51 | { |
52 | Error *err = NULL; | |
53 | ''', | |
83a02706 | 54 | name=c_name(name)) |
50f2bdc7 | 55 | push_indent() |
d195325b | 56 | |
622f557f KW |
57 | if base: |
58 | ret += mcgen(''' | |
a82b982e | 59 | visit_type_implicit_%(type)s(m, &(*obj)->%(c_name)s, &err); |
297a3646 MA |
60 | if (err) { |
61 | goto out; | |
62 | } | |
622f557f | 63 | ''', |
18df515e | 64 | type=type_name(base), c_name=c_name('base')) |
622f557f | 65 | |
6b5abc7d | 66 | for argname, argentry, optional in parse_args(members): |
06d64c62 MR |
67 | if optional: |
68 | ret += mcgen(''' | |
a82b982e EB |
69 | visit_optional(m, &(*obj)->has_%(c_name)s, "%(name)s", &err); |
70 | if (!err && (*obj)->has_%(c_name)s) { | |
06d64c62 | 71 | ''', |
18df515e | 72 | c_name=c_name(argname), name=argname) |
06d64c62 MR |
73 | push_indent() |
74 | ||
6b5abc7d | 75 | ret += mcgen(''' |
a82b982e | 76 | visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err); |
06d64c62 | 77 | ''', |
18df515e | 78 | type=type_name(argentry), c_name=c_name(argname), |
6b5abc7d | 79 | name=argname) |
06d64c62 MR |
80 | |
81 | if optional: | |
82 | pop_indent() | |
83 | ret += mcgen(''' | |
84 | } | |
297a3646 MA |
85 | ''') |
86 | ret += mcgen(''' | |
87 | if (err) { | |
88 | goto out; | |
89 | } | |
d195325b PB |
90 | ''') |
91 | ||
50f2bdc7 | 92 | pop_indent() |
297a3646 MA |
93 | if re.search('^ *goto out\\;', ret, re.MULTILINE): |
94 | ret += mcgen(''' | |
50f2bdc7 | 95 | |
297a3646 MA |
96 | out: |
97 | ''') | |
98 | ret += mcgen(''' | |
50f2bdc7 KW |
99 | error_propagate(errp, err); |
100 | } | |
101 | ''') | |
d131c897 KW |
102 | return ret |
103 | ||
104 | ||
5aa05d3f | 105 | def generate_visit_struct_body(name): |
d131c897 | 106 | ret = mcgen(''' |
297a3646 MA |
107 | Error *err = NULL; |
108 | ||
83a02706 | 109 | visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err); |
297a3646 MA |
110 | if (!err) { |
111 | if (*obj) { | |
83a02706 | 112 | visit_type_%(c_name)s_fields(m, obj, errp); |
297a3646 MA |
113 | } |
114 | visit_end_struct(m, &err); | |
50f2bdc7 | 115 | } |
297a3646 | 116 | error_propagate(errp, err); |
50f2bdc7 | 117 | ''', |
83a02706 | 118 | name=name, c_name=c_name(name)) |
d195325b | 119 | |
06d64c62 MR |
120 | return ret |
121 | ||
14d36307 KW |
122 | def generate_visit_struct(expr): |
123 | ||
fd41dd4e | 124 | name = expr['struct'] |
14d36307 | 125 | members = expr['data'] |
622f557f | 126 | base = expr.get('base') |
14d36307 | 127 | |
a82b982e | 128 | ret = generate_visit_struct_fields(name, members, base) |
50f2bdc7 KW |
129 | |
130 | ret += mcgen(''' | |
06d64c62 | 131 | |
638ca8ad | 132 | void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp) |
06d64c62 | 133 | { |
06d64c62 | 134 | ''', |
83a02706 | 135 | name=c_name(name)) |
d195325b | 136 | |
5aa05d3f | 137 | ret += generate_visit_struct_body(name) |
06d64c62 MR |
138 | |
139 | ret += mcgen(''' | |
06d64c62 MR |
140 | } |
141 | ''') | |
142 | return ret | |
143 | ||
5aa05d3f | 144 | def generate_visit_list(name): |
06d64c62 MR |
145 | return mcgen(''' |
146 | ||
638ca8ad | 147 | void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp) |
06d64c62 | 148 | { |
d195325b | 149 | Error *err = NULL; |
297a3646 | 150 | GenericList *i, **prev; |
06d64c62 | 151 | |
297a3646 MA |
152 | visit_start_list(m, name, &err); |
153 | if (err) { | |
154 | goto out; | |
155 | } | |
156 | ||
157 | for (prev = (GenericList **)obj; | |
158 | !err && (i = visit_next_list(m, prev, &err)) != NULL; | |
159 | prev = &i) { | |
160 | %(name)sList *native_i = (%(name)sList *)i; | |
161 | visit_type_%(name)s(m, &native_i->value, NULL, &err); | |
06d64c62 | 162 | } |
297a3646 MA |
163 | |
164 | error_propagate(errp, err); | |
165 | err = NULL; | |
166 | visit_end_list(m, &err); | |
167 | out: | |
168 | error_propagate(errp, err); | |
06d64c62 MR |
169 | } |
170 | ''', | |
fce384b8 | 171 | name=type_name(name)) |
06d64c62 | 172 | |
5aa05d3f | 173 | def generate_visit_enum(name): |
06d64c62 MR |
174 | return mcgen(''' |
175 | ||
638ca8ad | 176 | void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp) |
06d64c62 MR |
177 | { |
178 | visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp); | |
179 | } | |
180 | ''', | |
fce384b8 | 181 | name=c_name(name)) |
06d64c62 | 182 | |
811d04fd | 183 | def generate_visit_alternate(name, members): |
69dd62df KW |
184 | ret = mcgen(''' |
185 | ||
638ca8ad | 186 | void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp) |
69dd62df KW |
187 | { |
188 | Error *err = NULL; | |
189 | ||
297a3646 MA |
190 | visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err); |
191 | if (err) { | |
192 | goto out; | |
193 | } | |
194 | visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err); | |
195 | if (err) { | |
196 | goto out_end; | |
197 | } | |
198 | switch ((*obj)->kind) { | |
69dd62df | 199 | ''', |
d1f07c86 | 200 | name=c_name(name)) |
69dd62df | 201 | |
ab916fad | 202 | # For alternate, always use the default enum type automatically generated |
d1f07c86 EB |
203 | # as name + 'Kind' |
204 | disc_type = c_name(name) + 'Kind' | |
b0b58195 | 205 | |
69dd62df | 206 | for key in members: |
b52c4b9c | 207 | assert (members[key] in builtin_types.keys() |
69dd62df | 208 | or find_struct(members[key]) |
e775ba77 | 209 | or find_union(members[key]) |
ab916fad | 210 | or find_enum(members[key])), "Invalid alternate member" |
69dd62df | 211 | |
7c81c61f | 212 | enum_full_value = c_enum_const(disc_type, key) |
69dd62df | 213 | ret += mcgen(''' |
297a3646 MA |
214 | case %(enum_full_value)s: |
215 | visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); | |
216 | break; | |
69dd62df | 217 | ''', |
b0b58195 | 218 | enum_full_value = enum_full_value, |
69dd62df | 219 | c_type = type_name(members[key]), |
18df515e | 220 | c_name = c_name(key)) |
69dd62df KW |
221 | |
222 | ret += mcgen(''' | |
297a3646 MA |
223 | default: |
224 | abort(); | |
69dd62df | 225 | } |
297a3646 MA |
226 | out_end: |
227 | error_propagate(errp, err); | |
228 | err = NULL; | |
229 | visit_end_implicit_struct(m, &err); | |
230 | out: | |
231 | error_propagate(errp, err); | |
69dd62df KW |
232 | } |
233 | ''') | |
234 | ||
235 | return ret | |
236 | ||
237 | ||
0aef92b9 KW |
238 | def generate_visit_union(expr): |
239 | ||
240 | name = expr['union'] | |
241 | members = expr['data'] | |
242 | ||
243 | base = expr.get('base') | |
50f2bdc7 | 244 | discriminator = expr.get('discriminator') |
0aef92b9 | 245 | |
bceae769 WX |
246 | enum_define = discriminator_find_enum_define(expr) |
247 | if enum_define: | |
248 | # Use the enum type as discriminator | |
249 | ret = "" | |
857af5f0 | 250 | disc_type = c_name(enum_define['enum_name']) |
bceae769 | 251 | else: |
a8d4a2e4 | 252 | # There will always be a discriminator in the C switch code, by default |
bb337290 | 253 | # it is an enum type generated silently |
5aa05d3f | 254 | ret = generate_visit_enum(name + 'Kind') |
bb337290 | 255 | disc_type = c_name(name) + 'Kind' |
06d64c62 | 256 | |
50f2bdc7 | 257 | if base: |
a8d4a2e4 EB |
258 | assert discriminator |
259 | base_fields = find_struct(base)['data'].copy() | |
260 | del base_fields[discriminator] | |
a82b982e | 261 | ret += generate_visit_struct_fields(name, base_fields) |
50f2bdc7 | 262 | |
be3c7717 MA |
263 | if discriminator: |
264 | for key in members: | |
265 | ret += generate_visit_implicit_struct(members[key]) | |
266 | ||
06d64c62 MR |
267 | ret += mcgen(''' |
268 | ||
638ca8ad | 269 | void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp) |
06d64c62 | 270 | { |
dc8fb6df PB |
271 | Error *err = NULL; |
272 | ||
297a3646 MA |
273 | visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); |
274 | if (err) { | |
275 | goto out; | |
276 | } | |
277 | if (*obj) { | |
06d64c62 | 278 | ''', |
bb337290 | 279 | name=c_name(name)) |
06d64c62 | 280 | |
0aef92b9 | 281 | if base: |
50f2bdc7 | 282 | ret += mcgen(''' |
468866b8 | 283 | visit_type_%(name)s_fields(m, obj, &err); |
297a3646 MA |
284 | if (err) { |
285 | goto out_obj; | |
286 | } | |
50f2bdc7 | 287 | ''', |
857af5f0 | 288 | name=c_name(name)) |
0aef92b9 | 289 | |
7b75d9d6 | 290 | if not discriminator: |
0f61af3e | 291 | tag = 'kind' |
bceae769 | 292 | disc_key = "type" |
7b75d9d6 | 293 | else: |
0f61af3e | 294 | tag = discriminator |
bceae769 | 295 | disc_key = discriminator |
0aef92b9 | 296 | ret += mcgen(''' |
0f61af3e | 297 | visit_type_%(disc_type)s(m, &(*obj)->%(c_tag)s, "%(disc_key)s", &err); |
297a3646 MA |
298 | if (err) { |
299 | goto out_obj; | |
300 | } | |
cee2dedb MR |
301 | if (!visit_start_union(m, !!(*obj)->data, &err) || err) { |
302 | goto out_obj; | |
303 | } | |
0f61af3e | 304 | switch ((*obj)->%(c_tag)s) { |
0aef92b9 | 305 | ''', |
bceae769 | 306 | disc_type = disc_type, |
0f61af3e | 307 | c_tag=c_name(tag), |
bceae769 | 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 | ||
5aa05d3f | 345 | def generate_declaration(name, 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 | ||
5aa05d3f | 362 | def generate_enum_declaration(name): |
6540e9f3 | 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 | ||
5aa05d3f | 370 | def generate_decl_enum(name): |
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 | |
7c946bc4 | 377 | do_builtins = False |
8d3bc517 | 378 | |
2114f5a9 MA |
379 | (input_file, output_dir, do_c, do_h, prefix, opts) = \ |
380 | parse_command_line("b", ["builtins"]) | |
381 | ||
06d64c62 | 382 | for o, a in opts: |
2114f5a9 | 383 | if o in ("-b", "--builtins"): |
7c946bc4 | 384 | do_builtins = True |
8d3bc517 | 385 | |
12f8e1b9 | 386 | c_comment = ''' |
06d64c62 MR |
387 | /* |
388 | * schema-defined QAPI visitor functions | |
389 | * | |
390 | * Copyright IBM, Corp. 2011 | |
391 | * | |
392 | * Authors: | |
393 | * Anthony Liguori <aliguori@us.ibm.com> | |
394 | * | |
395 | * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. | |
396 | * See the COPYING.LIB file in the top-level directory. | |
397 | * | |
398 | */ | |
12f8e1b9 MA |
399 | ''' |
400 | h_comment = ''' | |
06d64c62 | 401 | /* |
297a3646 | 402 | * schema-defined QAPI visitor functions |
06d64c62 MR |
403 | * |
404 | * Copyright IBM, Corp. 2011 | |
405 | * | |
406 | * Authors: | |
407 | * Anthony Liguori <aliguori@us.ibm.com> | |
408 | * | |
409 | * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. | |
410 | * See the COPYING.LIB file in the top-level directory. | |
411 | * | |
412 | */ | |
12f8e1b9 MA |
413 | ''' |
414 | ||
415 | (fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, | |
416 | 'qapi-visit.c', 'qapi-visit.h', | |
417 | c_comment, h_comment) | |
06d64c62 | 418 | |
12f8e1b9 MA |
419 | fdef.write(mcgen(''' |
420 | #include "qemu-common.h" | |
421 | #include "%(prefix)sqapi-visit.h" | |
422 | ''', | |
423 | prefix = prefix)) | |
06d64c62 | 424 | |
12f8e1b9 | 425 | fdecl.write(mcgen(''' |
7b1b5d19 | 426 | #include "qapi/visitor.h" |
06d64c62 | 427 | #include "%(prefix)sqapi-types.h" |
7c946bc4 | 428 | |
06d64c62 | 429 | ''', |
12f8e1b9 | 430 | prefix=prefix)) |
06d64c62 | 431 | |
33aaad52 | 432 | exprs = parse_schema(input_file) |
06d64c62 | 433 | |
7c946bc4 MR |
434 | # to avoid header dependency hell, we always generate declarations |
435 | # for built-in types in our header files and simply guard them | |
436 | fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL")) | |
b52c4b9c | 437 | for typename in builtin_types.keys(): |
5aa05d3f | 438 | fdecl.write(generate_declaration(typename, builtin_type=True)) |
7c946bc4 MR |
439 | fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL")) |
440 | ||
441 | # ...this doesn't work for cases where we link in multiple objects that | |
442 | # have the functions defined, so we use -b option to provide control | |
443 | # over these cases | |
444 | if do_builtins: | |
b52c4b9c | 445 | for typename in builtin_types.keys(): |
5aa05d3f | 446 | fdef.write(generate_visit_list(typename)) |
7c946bc4 | 447 | |
06d64c62 | 448 | for expr in exprs: |
fd41dd4e | 449 | if expr.has_key('struct'): |
14d36307 | 450 | ret = generate_visit_struct(expr) |
5aa05d3f | 451 | ret += generate_visit_list(expr['struct']) |
06d64c62 MR |
452 | fdef.write(ret) |
453 | ||
5aa05d3f | 454 | ret = generate_declaration(expr['struct']) |
06d64c62 MR |
455 | fdecl.write(ret) |
456 | elif expr.has_key('union'): | |
0aef92b9 | 457 | ret = generate_visit_union(expr) |
5aa05d3f | 458 | ret += generate_visit_list(expr['union']) |
06d64c62 MR |
459 | fdef.write(ret) |
460 | ||
bceae769 WX |
461 | enum_define = discriminator_find_enum_define(expr) |
462 | ret = "" | |
463 | if not enum_define: | |
5aa05d3f MA |
464 | ret = generate_decl_enum('%sKind' % expr['union']) |
465 | ret += generate_declaration(expr['union']) | |
06d64c62 | 466 | fdecl.write(ret) |
ab916fad EB |
467 | elif expr.has_key('alternate'): |
468 | ret = generate_visit_alternate(expr['alternate'], expr['data']) | |
5aa05d3f | 469 | ret += generate_visit_list(expr['alternate']) |
ab916fad EB |
470 | fdef.write(ret) |
471 | ||
5aa05d3f MA |
472 | ret = generate_decl_enum('%sKind' % expr['alternate']) |
473 | ret += generate_declaration(expr['alternate']) | |
ab916fad | 474 | fdecl.write(ret) |
06d64c62 | 475 | elif expr.has_key('enum'): |
5aa05d3f MA |
476 | ret = generate_visit_list(expr['enum']) |
477 | ret += generate_visit_enum(expr['enum']) | |
06d64c62 MR |
478 | fdef.write(ret) |
479 | ||
5aa05d3f MA |
480 | ret = generate_decl_enum(expr['enum']) |
481 | ret += generate_enum_declaration(expr['enum']) | |
06d64c62 MR |
482 | fdecl.write(ret) |
483 | ||
12f8e1b9 | 484 | close_output(fdef, fdecl) |