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