1# 2# QAPI visitor generator 3# 4# Copyright IBM, Corp. 2011 5# Copyright (C) 2014-2016 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 qapi import * 16import re 17 18# visit_type_FOO_fields() is always emitted; track if a forward declaration 19# or implementation has already been output. 20struct_fields_seen = set() 21 22 23def gen_visit_decl(name, scalar=False): 24 c_type = c_name(name) + ' *' 25 if not scalar: 26 c_type += '*' 27 return mcgen(''' 28void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_type)sobj, Error **errp); 29''', 30 c_name=c_name(name), c_type=c_type) 31 32 33def gen_visit_fields_decl(typ): 34 if typ.name in struct_fields_seen: 35 return '' 36 struct_fields_seen.add(typ.name) 37 return mcgen(''' 38 39static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s *obj, Error **errp); 40''', 41 c_type=typ.c_name()) 42 43 44def gen_visit_struct_fields(name, base, members, variants): 45 ret = '' 46 47 if base: 48 ret += gen_visit_fields_decl(base) 49 if variants: 50 for var in variants.variants: 51 # Ugly special case for simple union TODO get rid of it 52 if not var.simple_union_type(): 53 ret += gen_visit_fields_decl(var.type) 54 55 struct_fields_seen.add(name) 56 ret += mcgen(''' 57 58static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s *obj, Error **errp) 59{ 60 Error *err = NULL; 61 62''', 63 c_name=c_name(name)) 64 65 if base: 66 ret += mcgen(''' 67 visit_type_%(c_type)s_fields(v, (%(c_type)s *)obj, &err); 68''', 69 c_type=base.c_name()) 70 ret += gen_err_check() 71 72 ret += gen_visit_fields(members, prefix='obj->') 73 74 if variants: 75 ret += mcgen(''' 76 switch (obj->%(c_name)s) { 77''', 78 c_name=c_name(variants.tag_member.name)) 79 80 for var in variants.variants: 81 # TODO ugly special case for simple union 82 simple_union_type = var.simple_union_type() 83 ret += mcgen(''' 84 case %(case)s: 85''', 86 case=c_enum_const(variants.tag_member.type.name, 87 var.name, 88 variants.tag_member.type.prefix)) 89 if simple_union_type: 90 ret += mcgen(''' 91 visit_type_%(c_type)s(v, "data", &obj->u.%(c_name)s, &err); 92''', 93 c_type=simple_union_type.c_name(), 94 c_name=c_name(var.name)) 95 else: 96 ret += mcgen(''' 97 visit_type_%(c_type)s_fields(v, &obj->u.%(c_name)s, &err); 98''', 99 c_type=var.type.c_name(), 100 c_name=c_name(var.name)) 101 ret += mcgen(''' 102 break; 103''') 104 105 ret += mcgen(''' 106 default: 107 abort(); 108 } 109''') 110 111 # 'goto out' produced for base, by gen_visit_fields() for each member, 112 # and if variants were present 113 if base or members or variants: 114 ret += mcgen(''' 115 116out: 117''') 118 ret += mcgen(''' 119 error_propagate(errp, err); 120} 121''') 122 return ret 123 124 125def gen_visit_list(name, element_type): 126 # FIXME: if *obj is NULL on entry, and the first visit_next_list() 127 # assigns to *obj, while a later one fails, we should clean up *obj 128 # rather than leaving it non-NULL. As currently written, the caller must 129 # call qapi_free_FOOList() to avoid a memory leak of the partial FOOList. 130 return mcgen(''' 131 132void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) 133{ 134 Error *err = NULL; 135 GenericList *i, **prev; 136 137 visit_start_list(v, name, &err); 138 if (err) { 139 goto out; 140 } 141 142 for (prev = (GenericList **)obj; 143 !err && (i = visit_next_list(v, prev, sizeof(**obj))) != NULL; 144 prev = &i) { 145 %(c_name)s *native_i = (%(c_name)s *)i; 146 visit_type_%(c_elt_type)s(v, NULL, &native_i->value, &err); 147 } 148 149 visit_end_list(v); 150out: 151 error_propagate(errp, err); 152} 153''', 154 c_name=c_name(name), c_elt_type=element_type.c_name()) 155 156 157def gen_visit_enum(name): 158 return mcgen(''' 159 160void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s *obj, Error **errp) 161{ 162 int value = *obj; 163 visit_type_enum(v, name, &value, %(c_name)s_lookup, errp); 164 *obj = value; 165} 166''', 167 c_name=c_name(name)) 168 169 170def gen_visit_alternate(name, variants): 171 promote_int = 'true' 172 ret = '' 173 for var in variants.variants: 174 if var.type.alternate_qtype() == 'QTYPE_QINT': 175 promote_int = 'false' 176 if isinstance(var.type, QAPISchemaObjectType): 177 ret += gen_visit_fields_decl(var.type) 178 179 ret += mcgen(''' 180 181void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) 182{ 183 Error *err = NULL; 184 185 visit_start_implicit_struct(v, (void**) obj, sizeof(%(c_name)s), &err); 186 if (err) { 187 goto out; 188 } 189 visit_get_next_type(v, name, &(*obj)->type, %(promote_int)s, &err); 190 if (err) { 191 goto out_obj; 192 } 193 switch ((*obj)->type) { 194''', 195 c_name=c_name(name), promote_int=promote_int) 196 197 for var in variants.variants: 198 ret += mcgen(''' 199 case %(case)s: 200''', 201 case=var.type.alternate_qtype()) 202 if isinstance(var.type, QAPISchemaObjectType): 203 ret += mcgen(''' 204 visit_start_struct(v, name, NULL, 0, &err); 205 if (err) { 206 break; 207 } 208 visit_type_%(c_type)s_fields(v, &(*obj)->u.%(c_name)s, &err); 209 error_propagate(errp, err); 210 err = NULL; 211 visit_end_struct(v, &err); 212''', 213 c_type=var.type.c_name(), 214 c_name=c_name(var.name)) 215 else: 216 ret += mcgen(''' 217 visit_type_%(c_type)s(v, name, &(*obj)->u.%(c_name)s, &err); 218''', 219 c_type=var.type.c_name(), 220 c_name=c_name(var.name)) 221 ret += mcgen(''' 222 break; 223''') 224 225 ret += mcgen(''' 226 default: 227 error_setg(&err, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", 228 "%(name)s"); 229 } 230out_obj: 231 visit_end_implicit_struct(v); 232out: 233 error_propagate(errp, err); 234} 235''', 236 name=name) 237 238 return ret 239 240 241def gen_visit_object(name, base, members, variants): 242 ret = gen_visit_struct_fields(name, base, members, variants) 243 244 # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to 245 # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj 246 # rather than leaving it non-NULL. As currently written, the caller must 247 # call qapi_free_FOO() to avoid a memory leak of the partial FOO. 248 ret += mcgen(''' 249 250void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) 251{ 252 Error *err = NULL; 253 254 visit_start_struct(v, name, (void **)obj, sizeof(%(c_name)s), &err); 255 if (err) { 256 goto out; 257 } 258 if (!*obj) { 259 goto out_obj; 260 } 261 visit_type_%(c_name)s_fields(v, *obj, &err); 262 error_propagate(errp, err); 263 err = NULL; 264out_obj: 265 visit_end_struct(v, &err); 266out: 267 error_propagate(errp, err); 268} 269''', 270 c_name=c_name(name)) 271 272 return ret 273 274 275class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): 276 def __init__(self): 277 self.decl = None 278 self.defn = None 279 self._btin = None 280 281 def visit_begin(self, schema): 282 self.decl = '' 283 self.defn = '' 284 self._btin = guardstart('QAPI_VISIT_BUILTIN') 285 286 def visit_end(self): 287 # To avoid header dependency hell, we always generate 288 # declarations for built-in types in our header files and 289 # simply guard them. See also do_builtins (command line 290 # option -b). 291 self._btin += guardend('QAPI_VISIT_BUILTIN') 292 self.decl = self._btin + self.decl 293 self._btin = None 294 295 def visit_needed(self, entity): 296 # Visit everything except implicit objects 297 return not (entity.is_implicit() and 298 isinstance(entity, QAPISchemaObjectType)) 299 300 def visit_enum_type(self, name, info, values, prefix): 301 # Special case for our lone builtin enum type 302 # TODO use something cleaner than existence of info 303 if not info: 304 self._btin += gen_visit_decl(name, scalar=True) 305 if do_builtins: 306 self.defn += gen_visit_enum(name) 307 else: 308 self.decl += gen_visit_decl(name, scalar=True) 309 self.defn += gen_visit_enum(name) 310 311 def visit_array_type(self, name, info, element_type): 312 decl = gen_visit_decl(name) 313 defn = gen_visit_list(name, element_type) 314 if isinstance(element_type, QAPISchemaBuiltinType): 315 self._btin += decl 316 if do_builtins: 317 self.defn += defn 318 else: 319 self.decl += decl 320 self.defn += defn 321 322 def visit_object_type(self, name, info, base, members, variants): 323 self.decl += gen_visit_decl(name) 324 self.defn += gen_visit_object(name, base, members, variants) 325 326 def visit_alternate_type(self, name, info, variants): 327 self.decl += gen_visit_decl(name) 328 self.defn += gen_visit_alternate(name, variants) 329 330# If you link code generated from multiple schemata, you want only one 331# instance of the code for built-in types. Generate it only when 332# do_builtins, enabled by command line option -b. See also 333# QAPISchemaGenVisitVisitor.visit_end(). 334do_builtins = False 335 336(input_file, output_dir, do_c, do_h, prefix, opts) = \ 337 parse_command_line("b", ["builtins"]) 338 339for o, a in opts: 340 if o in ("-b", "--builtins"): 341 do_builtins = True 342 343c_comment = ''' 344/* 345 * schema-defined QAPI visitor functions 346 * 347 * Copyright IBM, Corp. 2011 348 * 349 * Authors: 350 * Anthony Liguori <aliguori@us.ibm.com> 351 * 352 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 353 * See the COPYING.LIB file in the top-level directory. 354 * 355 */ 356''' 357h_comment = ''' 358/* 359 * schema-defined QAPI visitor functions 360 * 361 * Copyright IBM, Corp. 2011 362 * 363 * Authors: 364 * Anthony Liguori <aliguori@us.ibm.com> 365 * 366 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 367 * See the COPYING.LIB file in the top-level directory. 368 * 369 */ 370''' 371 372(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, 373 'qapi-visit.c', 'qapi-visit.h', 374 c_comment, h_comment) 375 376fdef.write(mcgen(''' 377#include "qemu/osdep.h" 378#include "qemu-common.h" 379#include "%(prefix)sqapi-visit.h" 380''', 381 prefix=prefix)) 382 383fdecl.write(mcgen(''' 384#include "qapi/visitor.h" 385#include "qapi/qmp/qerror.h" 386#include "%(prefix)sqapi-types.h" 387 388''', 389 prefix=prefix)) 390 391schema = QAPISchema(input_file) 392gen = QAPISchemaGenVisitVisitor() 393schema.visit(gen) 394fdef.write(gen.defn) 395fdecl.write(gen.decl) 396 397close_output(fdef, fdecl) 398