1#!/usr/bin/python 2 3import os 4import sys 5 6sys.path.append('{}/tools/libxl'.format(os.environ['XEN_ROOT'])) 7import idl 8 9# Go versions of some builtin types. 10# Append the libxl-defined builtins after IDL parsing. 11builtin_type_names = { 12 idl.bool.typename: 'bool', 13 idl.string.typename: 'string', 14 idl.integer.typename: 'int', 15 idl.uint8.typename: 'byte', 16 idl.uint16.typename: 'uint16', 17 idl.uint32.typename: 'uint32', 18 idl.uint64.typename: 'uint64', 19} 20 21# Some go keywords that conflict with field names in libxl structs. 22go_keywords = ['type', 'func'] 23 24go_builtin_types = ['bool', 'string', 'int', 'byte', 25 'uint16', 'uint32', 'uint64'] 26 27# cgo preamble for xenlight_helpers.go, created during type generation and 28# written later. 29cgo_helpers_preamble = [] 30 31def xenlight_golang_generate_types(path = None, types = None, comment = None): 32 """ 33 Generate a .go file (types.gen.go by default) 34 that contains a Go type for each type in types. 35 """ 36 if path is None: 37 path = 'types.gen.go' 38 39 with open(path, 'w') as f: 40 if comment is not None: 41 f.write(comment) 42 f.write('package xenlight\n\n') 43 44 for ty in types: 45 (tdef, extras) = xenlight_golang_type_define(ty) 46 47 f.write(tdef) 48 f.write('\n') 49 50 # Append extra types 51 for extra in extras: 52 f.write(extra) 53 f.write('\n') 54 55def xenlight_golang_type_define(ty = None): 56 """ 57 Generate the Go type definition of ty. 58 59 Return a tuple that contains a string with the 60 type definition, and a (potentially empty) list 61 of extra definitions that are associated with 62 this type. 63 """ 64 if isinstance(ty, idl.Enumeration): 65 return (xenlight_golang_define_enum(ty), []) 66 67 elif isinstance(ty, idl.Aggregate): 68 return xenlight_golang_define_struct(ty) 69 70def xenlight_golang_define_enum(ty = None): 71 s = '' 72 typename = '' 73 74 if ty.typename is not None: 75 typename = xenlight_golang_fmt_name(ty.typename) 76 s += 'type {} int\n'.format(typename) 77 78 # Start const block 79 s += 'const(\n' 80 81 for v in ty.values: 82 name = xenlight_golang_fmt_name(v.name) 83 s += '{} {} = {}\n'.format(name, typename, v.value) 84 85 # End const block 86 s += ')\n' 87 88 return s 89 90def xenlight_golang_define_struct(ty = None, typename = None, nested = False): 91 s = '' 92 extras = [] 93 name = '' 94 95 if typename is not None: 96 name = xenlight_golang_fmt_name(typename) 97 else: 98 name = xenlight_golang_fmt_name(ty.typename) 99 100 # Begin struct definition 101 if nested: 102 s += '{} struct {{\n'.format(name) 103 else: 104 s += 'type {} struct {{\n'.format(name) 105 106 # Write struct fields 107 for f in ty.fields: 108 if f.type.typename is not None: 109 if isinstance(f.type, idl.Array): 110 typename = f.type.elem_type.typename 111 typename = xenlight_golang_fmt_name(typename) 112 name = xenlight_golang_fmt_name(f.name) 113 114 s += '{} []{}\n'.format(name, typename) 115 else: 116 typename = f.type.typename 117 typename = xenlight_golang_fmt_name(typename) 118 name = xenlight_golang_fmt_name(f.name) 119 120 s += '{} {}\n'.format(name, typename) 121 122 elif isinstance(f.type, idl.Struct): 123 r = xenlight_golang_define_struct(f.type, typename=f.name, nested=True) 124 125 s += r[0] 126 extras.extend(r[1]) 127 128 elif isinstance(f.type, idl.KeyedUnion): 129 r = xenlight_golang_define_union(f.type, ty.typename, f.name) 130 131 s += r[0] 132 extras.extend(r[1]) 133 134 else: 135 raise Exception('type {} not supported'.format(f.type)) 136 137 # End struct definition 138 s += '}\n' 139 140 return (s,extras) 141 142def xenlight_golang_define_union(ty = None, struct_name = '', union_name = ''): 143 """ 144 Generate the Go translation of a KeyedUnion. 145 146 Define an unexported interface to be used as 147 the type of the union. Then, define a struct 148 for each field of the union which implements 149 that interface. 150 """ 151 s = '' 152 extras = [] 153 154 interface_name = '{}_{}_union'.format(struct_name, ty.keyvar.name) 155 interface_name = xenlight_golang_fmt_name(interface_name, exported=False) 156 157 s += 'type {} interface {{\n'.format(interface_name) 158 s += 'is{}()\n'.format(interface_name) 159 s += '}\n' 160 161 extras.append(s) 162 163 for f in ty.fields: 164 if f.type is None: 165 continue 166 167 # Define struct 168 name = '{}_{}_union_{}'.format(struct_name, ty.keyvar.name, f.name) 169 r = xenlight_golang_define_struct(f.type, typename=name) 170 extras.append(r[0]) 171 extras.extend(r[1]) 172 173 # This typeof trick ensures that the fields used in the cgo struct 174 # used for marshaling are the same as the fields of the union in the 175 # actual C type, and avoids re-defining all of those fields. 176 s = 'typedef typeof(((struct {} *)NULL)->{}.{}){};' 177 s = s.format(struct_name, union_name, f.name, name) 178 cgo_helpers_preamble.append(s) 179 180 # Define function to implement 'union' interface 181 name = xenlight_golang_fmt_name(name) 182 s = 'func (x {}) is{}(){{}}\n'.format(name, interface_name) 183 extras.append(s) 184 185 fname = xenlight_golang_fmt_name(ty.keyvar.name) 186 ftype = xenlight_golang_fmt_name(ty.keyvar.type.typename) 187 s = '{} {}\n'.format(fname, ftype) 188 189 fname = xenlight_golang_fmt_name('{}_union'.format(ty.keyvar.name)) 190 s += '{} {}\n'.format(fname, interface_name) 191 192 return (s,extras) 193 194def xenlight_golang_generate_helpers(path = None, types = None, comment = None): 195 """ 196 Generate a .go file (helpers.gen.go by default) 197 that contains helper functions for marshaling between 198 C and Go types. 199 """ 200 if path is None: 201 path = 'helpers.gen.go' 202 203 with open(path, 'w') as f: 204 if comment is not None: 205 f.write(comment) 206 f.write('package xenlight\n\n') 207 f.write('import (\n"unsafe"\n"errors"\n"fmt"\n)\n') 208 209 # Cgo preamble 210 f.write('/*\n') 211 f.write('#cgo LDFLAGS: -lxenlight\n') 212 f.write('#include <stdlib.h>\n') 213 f.write('#include <libxl.h>\n') 214 f.write('\n') 215 216 for s in cgo_helpers_preamble: 217 f.write(s) 218 f.write('\n') 219 220 f.write('*/\nimport "C"\n') 221 222 for ty in types: 223 if not isinstance(ty, idl.Struct): 224 continue 225 226 f.write(xenlight_golang_define_constructor(ty)) 227 f.write('\n') 228 229 (fdef, extras) = xenlight_golang_define_from_C(ty) 230 231 f.write(fdef) 232 f.write('\n') 233 234 for extra in extras: 235 f.write(extra) 236 f.write('\n') 237 238 f.write(xenlight_golang_define_to_C(ty)) 239 f.write('\n') 240 241def xenlight_golang_define_from_C(ty = None): 242 """ 243 Define the fromC marshaling function for the type 244 represented by ty. 245 """ 246 func = 'func (x *{}) fromC(xc *C.{}) error {{\n {}\n return nil}}\n' 247 248 goname = xenlight_golang_fmt_name(ty.typename) 249 cname = ty.typename 250 251 body = '' 252 extras = [] 253 254 for f in ty.fields: 255 if f.type.typename is not None: 256 if isinstance(f.type, idl.Array): 257 body += xenlight_golang_array_from_C(f) 258 continue 259 260 body += xenlight_golang_convert_from_C(f) 261 262 elif isinstance(f.type, idl.Struct): 263 # Go through the fields of the anonymous nested struct. 264 for nf in f.type.fields: 265 body += xenlight_golang_convert_from_C(nf,outer_name=f.name) 266 267 elif isinstance(f.type, idl.KeyedUnion): 268 r = xenlight_golang_union_from_C(f.type, f.name, ty.typename) 269 270 body += r[0] 271 extras.extend(r[1]) 272 273 else: 274 raise Exception('type {} not supported'.format(f.type)) 275 276 return (func.format(goname, cname, body), extras) 277 278def xenlight_golang_convert_from_C(ty = None, outer_name = None, cvarname = None): 279 """ 280 Returns a line of Go code that converts the C type represented 281 by ty to its corresponding Go type. 282 283 If outer_name is set, the type is treated as nested within another field 284 named outer_name. 285 """ 286 s = '' 287 288 # Use 'xc' as the name for the C variable unless otherwise specified 289 if cvarname is None: 290 cvarname = 'xc' 291 292 gotypename = xenlight_golang_fmt_name(ty.type.typename) 293 goname = xenlight_golang_fmt_name(ty.name) 294 cname = ty.name 295 296 # In cgo, C names that conflict with Go keywords can be 297 # accessed by prepending an underscore to the name. 298 if cname in go_keywords: 299 cname = '_' + cname 300 301 # If outer_name is set, treat this as nested. 302 if outer_name is not None: 303 goname = '{}.{}'.format(xenlight_golang_fmt_name(outer_name), goname) 304 cname = '{}.{}'.format(outer_name, cname) 305 306 # Types that satisfy this condition can be easily casted or 307 # converted to a Go builtin type. 308 is_castable = (ty.type.json_parse_type == 'JSON_INTEGER' or 309 isinstance(ty.type, idl.Enumeration) or 310 gotypename in go_builtin_types) 311 312 if not is_castable: 313 # If the type is not castable, we need to call its fromC 314 # function. 315 s += 'if err := x.{}.fromC(&{}.{});'.format(goname,cvarname,cname) 316 s += 'err != nil {{\nreturn fmt.Errorf("converting field {}: %v", err)\n}}\n'.format(goname) 317 318 elif gotypename == 'string': 319 # Use the cgo helper for converting C strings. 320 s += 'x.{} = C.GoString({}.{})\n'.format(goname,cvarname,cname) 321 322 else: 323 s += 'x.{} = {}({}.{})\n'.format(goname,gotypename,cvarname,cname) 324 325 return s 326 327def xenlight_golang_union_from_C(ty = None, union_name = '', struct_name = ''): 328 extras = [] 329 330 keyname = ty.keyvar.name 331 gokeyname = xenlight_golang_fmt_name(keyname) 332 keytype = ty.keyvar.type.typename 333 gokeytype = xenlight_golang_fmt_name(keytype) 334 field_name = xenlight_golang_fmt_name('{}_union'.format(keyname)) 335 336 interface_name = '{}_{}_union'.format(struct_name, keyname) 337 interface_name = xenlight_golang_fmt_name(interface_name, exported=False) 338 339 cgo_keyname = keyname 340 if cgo_keyname in go_keywords: 341 cgo_keyname = '_' + cgo_keyname 342 343 cases = {} 344 345 for f in ty.fields: 346 val = '{}_{}'.format(keytype, f.name) 347 val = xenlight_golang_fmt_name(val) 348 349 # Add to list of cases to make for the switch 350 # statement below. 351 cases[f.name] = (val, f.type) 352 353 if f.type is None: 354 continue 355 356 # Define fromC func for 'union' struct. 357 typename = '{}_{}_union_{}'.format(struct_name,keyname,f.name) 358 gotypename = xenlight_golang_fmt_name(typename) 359 360 # Define the function here. The cases for keyed unions are a little 361 # different. 362 s = 'func (x *{}) fromC(xc *C.{}) error {{\n'.format(gotypename,struct_name) 363 s += 'if {}(xc.{}) != {} {{\n'.format(gokeytype,cgo_keyname,val) 364 err_string = '"expected union key {}"'.format(val) 365 s += 'return errors.New({})\n'.format(err_string) 366 s += '}\n\n' 367 s += 'tmp := (*C.{})(unsafe.Pointer(&xc.{}[0]))\n'.format(typename,union_name) 368 369 for nf in f.type.fields: 370 s += xenlight_golang_convert_from_C(nf,cvarname='tmp') 371 372 s += 'return nil\n' 373 s += '}\n' 374 375 extras.append(s) 376 377 s = 'x.{} = {}(xc.{})\n'.format(gokeyname,gokeytype,cgo_keyname) 378 s += 'switch x.{}{{\n'.format(gokeyname) 379 380 # Create switch statement to determine which 'union element' 381 # to populate in the Go struct. 382 for case_name, case_tuple in sorted(cases.items()): 383 (case_val, case_type) = case_tuple 384 385 s += 'case {}:\n'.format(case_val) 386 387 if case_type is None: 388 s += "x.{} = nil\n".format(field_name) 389 continue 390 391 gotype = '{}_{}_union_{}'.format(struct_name,keyname,case_name) 392 gotype = xenlight_golang_fmt_name(gotype) 393 goname = '{}_{}'.format(keyname,case_name) 394 goname = xenlight_golang_fmt_name(goname,exported=False) 395 396 s += 'var {} {}\n'.format(goname, gotype) 397 s += 'if err := {}.fromC(xc);'.format(goname) 398 s += 'err != nil {{\n return fmt.Errorf("converting field {}: %v", err)\n}}\n'.format(goname) 399 400 s += 'x.{} = {}\n'.format(field_name, goname) 401 402 # End switch statement 403 s += 'default:\n' 404 err_string = '"invalid union key \'%v\'", x.{}'.format(gokeyname) 405 s += 'return fmt.Errorf({})'.format(err_string) 406 s += '}\n' 407 408 return (s,extras) 409 410def xenlight_golang_array_from_C(ty = None): 411 """ 412 Convert C array to Go slice using the method 413 described here: 414 415 https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices 416 """ 417 s = '' 418 419 gotypename = xenlight_golang_fmt_name(ty.type.elem_type.typename) 420 goname = xenlight_golang_fmt_name(ty.name) 421 ctypename = ty.type.elem_type.typename 422 cname = ty.name 423 cslice = 'c{}'.format(goname) 424 clenvar = ty.type.lenvar.name 425 426 s += 'x.{} = nil\n'.format(goname) 427 s += 'if n := int(xc.{}); n > 0 {{\n'.format(clenvar) 428 s += '{} := '.format(cslice) 429 s +='(*[1<<28]C.{})(unsafe.Pointer(xc.{}))[:n:n]\n'.format(ctypename, cname) 430 s += 'x.{} = make([]{}, n)\n'.format(goname, gotypename) 431 s += 'for i, v := range {} {{\n'.format(cslice) 432 433 is_enum = isinstance(ty.type.elem_type,idl.Enumeration) 434 if gotypename in go_builtin_types or is_enum: 435 s += 'x.{}[i] = {}(v)\n'.format(goname, gotypename) 436 else: 437 s += 'if err := x.{}[i].fromC(&v); err != nil {{\n'.format(goname) 438 s += 'return fmt.Errorf("converting field {}: %v", err) }}\n'.format(goname) 439 440 s += '}\n}\n' 441 442 return s 443 444def xenlight_golang_define_to_C(ty = None, typename = None, nested = False): 445 """ 446 Define the toC marshaling function for the type 447 represented by ty. 448 """ 449 func = 'func (x *{}) toC(xc *C.{}) (err error){{{}\n return nil\n }}\n' 450 body = '' 451 452 if ty.dispose_fn is not None: 453 body += 'defer func(){{\nif err != nil{{\nC.{}(xc)}}\n}}()\n\n'.format(ty.dispose_fn) 454 455 goname = xenlight_golang_fmt_name(ty.typename) 456 cname = ty.typename 457 458 for f in ty.fields: 459 if f.type.typename is not None: 460 if isinstance(f.type, idl.Array): 461 body += xenlight_golang_array_to_C(f) 462 continue 463 464 body += xenlight_golang_convert_to_C(f) 465 466 elif isinstance(f.type, idl.Struct): 467 for nf in f.type.fields: 468 body += xenlight_golang_convert_to_C(nf, outer_name=f.name) 469 470 elif isinstance(f.type, idl.KeyedUnion): 471 body += xenlight_golang_union_to_C(f.type, f.name, ty.typename) 472 473 else: 474 raise Exception('type {} not supported'.format(f.type)) 475 476 return func.format(goname, cname, body) 477 478def xenlight_golang_convert_to_C(ty = None, outer_name = None, 479 govarname = None, cvarname = None): 480 """ 481 Returns a line of Go code that converts the Go type represented 482 by ty to its corresponding Go type. 483 484 If outer_name is set, the type is treated as nested within another field 485 named outer_name. 486 """ 487 s = '' 488 489 # Use 'xc' as the name for the C variable unless otherwise specified. 490 if cvarname is None: 491 cvarname = 'xc' 492 493 # Use 'x' as the name for the Go variable unless otherwise specified. 494 if govarname is None: 495 govarname = 'x' 496 497 gotypename = xenlight_golang_fmt_name(ty.type.typename) 498 ctypename = ty.type.typename 499 goname = xenlight_golang_fmt_name(ty.name) 500 cname = ty.name 501 502 # In cgo, C names that conflict with Go keywords can be 503 # accessed by prepending an underscore to the name. 504 if cname in go_keywords: 505 cname = '_' + cname 506 507 # If outer_name is set, treat this as nested. 508 if outer_name is not None: 509 goname = '{}.{}'.format(xenlight_golang_fmt_name(outer_name), goname) 510 cname = '{}.{}'.format(outer_name, cname) 511 512 is_castable = (ty.type.json_parse_type == 'JSON_INTEGER' or 513 isinstance(ty.type, idl.Enumeration) or 514 gotypename in go_builtin_types) 515 516 if not is_castable: 517 s += 'if err := {}.{}.toC(&{}.{}); err != nil {{\n'.format(govarname,goname, 518 cvarname,cname) 519 s += 'return fmt.Errorf("converting field {}: %v", err)\n}}\n'.format(goname) 520 521 elif gotypename == 'string': 522 # Use the cgo helper for converting C strings. 523 s += 'if {}.{} != "" {{\n'.format(govarname,goname) 524 s += '{}.{} = C.CString({}.{})}}\n'.format(cvarname,cname, 525 govarname,goname) 526 527 else: 528 s += '{}.{} = C.{}({}.{})\n'.format(cvarname,cname,ctypename, 529 govarname,goname) 530 531 return s 532 533def xenlight_golang_union_to_C(ty = None, union_name = '', 534 struct_name = ''): 535 keyname = ty.keyvar.name 536 gokeyname = xenlight_golang_fmt_name(keyname) 537 keytype = ty.keyvar.type.typename 538 gokeytype = xenlight_golang_fmt_name(keytype) 539 540 interface_name = '{}_{}_union'.format(struct_name, keyname) 541 interface_name = xenlight_golang_fmt_name(interface_name, exported=False) 542 543 cgo_keyname = keyname 544 if cgo_keyname in go_keywords: 545 cgo_keyname = '_' + cgo_keyname 546 547 548 s = 'xc.{} = C.{}(x.{})\n'.format(cgo_keyname,keytype,gokeyname) 549 s += 'switch x.{}{{\n'.format(gokeyname) 550 551 # Create switch statement to determine how to populate the C union. 552 for f in ty.fields: 553 key_val = '{}_{}'.format(keytype, f.name) 554 key_val = xenlight_golang_fmt_name(key_val) 555 556 s += 'case {}:\n'.format(key_val) 557 558 if f.type is None: 559 s += "break\n" 560 continue 561 562 cgotype = '{}_{}_union_{}'.format(struct_name,keyname,f.name) 563 gotype = xenlight_golang_fmt_name(cgotype) 564 565 field_name = xenlight_golang_fmt_name('{}_union'.format(keyname)) 566 s += 'tmp, ok := x.{}.({})\n'.format(field_name,gotype) 567 s += 'if !ok {\n' 568 s += 'return errors.New("wrong type for union key {}")\n'.format(keyname) 569 s += '}\n' 570 571 s += 'var {} C.{}\n'.format(f.name,cgotype) 572 for uf in f.type.fields: 573 s += xenlight_golang_convert_to_C(uf,cvarname=f.name, 574 govarname='tmp') 575 576 # The union is still represented as Go []byte. 577 s += '{}Bytes := C.GoBytes(unsafe.Pointer(&{}),C.sizeof_{})\n'.format(f.name, 578 f.name, 579 cgotype) 580 s += 'copy(xc.{}[:],{}Bytes)\n'.format(union_name,f.name) 581 582 # End switch statement 583 s += 'default:\n' 584 err_string = '"invalid union key \'%v\'", x.{}'.format(gokeyname) 585 s += 'return fmt.Errorf({})'.format(err_string) 586 s += '}\n' 587 588 return s 589 590def xenlight_golang_array_to_C(ty = None): 591 s = '' 592 593 gotypename = xenlight_golang_fmt_name(ty.type.elem_type.typename) 594 goname = xenlight_golang_fmt_name(ty.name) 595 ctypename = ty.type.elem_type.typename 596 cname = ty.name 597 clenvar = ty.type.lenvar.name 598 golenvar = xenlight_golang_fmt_name(clenvar,exported=False) 599 600 is_enum = isinstance(ty.type.elem_type,idl.Enumeration) 601 if gotypename in go_builtin_types or is_enum: 602 s += 'if {} := len(x.{}); {} > 0 {{\n'.format(golenvar,goname,golenvar) 603 s += 'xc.{} = (*C.{})(C.malloc(C.size_t({}*{})))\n'.format(cname,ctypename, 604 golenvar,golenvar) 605 s += 'xc.{} = C.int({})\n'.format(clenvar,golenvar) 606 s += 'c{} := (*[1<<28]C.{})(unsafe.Pointer(xc.{}))[:{}:{}]\n'.format(goname, 607 ctypename,cname, 608 golenvar,golenvar) 609 s += 'for i,v := range x.{} {{\n'.format(goname) 610 s += 'c{}[i] = C.{}(v)\n'.format(goname,ctypename) 611 s += '}\n}\n' 612 613 return s 614 615 s += 'if {} := len(x.{}); {} > 0 {{\n'.format(golenvar,goname,golenvar) 616 s += 'xc.{} = (*C.{})(C.malloc(C.ulong({})*C.sizeof_{}))\n'.format(cname,ctypename, 617 golenvar,ctypename) 618 s += 'xc.{} = C.int({})\n'.format(clenvar,golenvar) 619 s += 'c{} := (*[1<<28]C.{})(unsafe.Pointer(xc.{}))[:{}:{}]\n'.format(goname, 620 ctypename,cname, 621 golenvar,golenvar) 622 s += 'for i,v := range x.{} {{\n'.format(goname) 623 s += 'if err := v.toC(&c{}[i]); err != nil {{\n'.format(goname) 624 s += 'return fmt.Errorf("converting field {}: %v", err)\n'.format(goname) 625 s += '}\n}\n}\n' 626 627 return s 628 629def xenlight_golang_define_constructor(ty = None): 630 s = '' 631 632 ctypename = ty.typename 633 gotypename = xenlight_golang_fmt_name(ctypename) 634 635 # Since this func is exported, add a comment as per Go conventions. 636 s += '// New{} returns an instance of {}'.format(gotypename,gotypename) 637 s += ' initialized with defaults.\n' 638 639 # If a struct has a keyed union, an extra argument is 640 # required in the function signature, and an extra _init 641 # call is needed. 642 params = [] 643 init_fns = [] 644 645 # Add call to parent init_fn first. 646 init_fns.append('C.{}(&xc)'.format(ty.init_fn)) 647 648 for f in ty.fields: 649 if not isinstance(f.type, idl.KeyedUnion): 650 continue 651 652 param = f.type.keyvar 653 654 param_ctype = param.type.typename 655 param_gotype = xenlight_golang_fmt_name(param_ctype) 656 param_goname = xenlight_golang_fmt_name(param.name,exported=False) 657 658 # Serveral keyed unions use 'type' as the key variable name. In 659 # that case, prepend the first letter of the Go type name. 660 if param_goname == 'type': 661 param_goname = '{}type'.format(param_gotype.lower()[0]) 662 663 # Add call to keyed union's init_fn. 664 init_fns.append('C.{}_{}(&xc, C.{}({}))'.format(ty.init_fn, 665 param.name, 666 param_ctype, 667 param_goname)) 668 669 # Add to params list. 670 params.append('{} {}'.format(param_goname, param_gotype)) 671 672 # Define function 673 s += 'func New{}({}) (*{}, error) {{\n'.format(gotypename, 674 ','.join(params), 675 gotypename) 676 677 # Declare variables. 678 s += 'var (\nx {}\nxc C.{})\n\n'.format(gotypename, ctypename) 679 680 # Write init_fn calls. 681 s += '\n'.join(init_fns) 682 s += '\n' 683 684 # Make sure dispose_fn get's called when constructor 685 # returns. 686 if ty.dispose_fn is not None: 687 s += 'defer C.{}(&xc)\n'.format(ty.dispose_fn) 688 689 s += '\n' 690 691 # Call fromC to initialize Go type. 692 s += 'if err := x.fromC(&xc); err != nil {\n' 693 s += 'return nil, err }\n\n' 694 s += 'return &x, nil}\n' 695 696 return s 697 698def xenlight_golang_fmt_name(name, exported = True): 699 """ 700 Take a given type name and return an 701 appropriate Go type name. 702 """ 703 if name in builtin_type_names.keys(): 704 return builtin_type_names[name] 705 706 # Name is not a builtin, format it for Go. 707 words = name.split('_') 708 709 # Remove 'libxl' prefix 710 if words[0].lower() == 'libxl': 711 words.remove(words[0]) 712 713 if exported: 714 return ''.join(x.title() for x in words) 715 716 return words[0] + ''.join(x.title() for x in words[1:]) 717 718if __name__ == '__main__': 719 idlname = sys.argv[1] 720 721 (builtins, types) = idl.parse(idlname) 722 723 for b in builtins: 724 name = b.typename 725 builtin_type_names[name] = xenlight_golang_fmt_name(name) 726 727 header_comment="""// DO NOT EDIT. 728// 729// This file is generated by: 730// {} 731// 732 733""".format(' '.join(sys.argv)) 734 735 xenlight_golang_generate_types(types=types, 736 comment=header_comment) 737 xenlight_golang_generate_helpers(types=types, 738 comment=header_comment) 739