1# -*- Mode: Python; py-indent-offset: 4 -*- 2import copy 3import sys 4 5def get_valid_scheme_definitions(defs): 6 return [x for x in defs if isinstance(x, tuple) and len(x) >= 2] 7 8def unescape(s): 9 s = s.replace('\r\n', '\\r\\n').replace('\t', '\\t') 10 return s.replace('\r', '\\r').replace('\n', '\\n') 11 12def make_docstring(lines): 13 return "(char *) " + '\n'.join(['"%s"' % unescape(s) for s in lines]) 14 15# New Parameter class, wich emulates a tuple for compatibility reasons 16class Parameter(object): 17 def __init__(self, ptype, pname, pdflt, pnull, pdir=None): 18 self.ptype = ptype 19 self.pname = pname 20 self.pdflt = pdflt 21 self.pnull = pnull 22 self.pdir = pdir 23 24 def __len__(self): return 4 25 def __getitem__(self, i): 26 return (self.ptype, self.pname, self.pdflt, self.pnull)[i] 27 28 def merge(self, old): 29 if old.pdflt is not None: 30 self.pdflt = old.pdflt 31 if old.pnull is not None: 32 self.pnull = old.pnull 33 34# We currently subclass 'str' to make impact on the rest of codegen as 35# little as possible. Later we can subclass 'object' instead, but 36# then we must find and adapt all places which expect return types to 37# be strings. 38class ReturnType(str): 39 def __new__(cls, *args, **kwds): 40 return str.__new__(cls, *args[:1]) 41 def __init__(self, type_name, optional=False): 42 str.__init__(self) 43 self.optional = optional 44 45# Parameter for property based constructors 46class Property(object): 47 def __init__(self, pname, optional, argname): 48 self.pname = pname 49 self.optional = optional 50 self.argname = argname 51 52 def __len__(self): return 4 53 def __getitem__(self, i): 54 return ('', self.pname, self.optional, self.argname)[i] 55 56 def merge(self, old): 57 if old.optional is not None: 58 self.optional = old.optional 59 if old.argname is not None: 60 self.argname = old.argname 61 62 63class Definition(object): 64 docstring = "NULL" 65 66 def py_name(self): 67 return '%s.%s' % (self.module, self.name) 68 69 py_name = property(py_name) 70 71 def __init__(self, *args): 72 """Create a new defs object of this type. The arguments are the 73 components of the definition""" 74 raise RuntimeError("this is an abstract class") 75 76 def merge(self, old): 77 """Merge in customisations from older version of definition""" 78 raise RuntimeError("this is an abstract class") 79 80 def write_defs(self, fp=sys.stdout): 81 """write out this definition in defs file format""" 82 raise RuntimeError("this is an abstract class") 83 84 def guess_return_value_ownership(self): 85 "return 1 if caller owns return value" 86 if getattr(self, 'is_constructor_of', False): 87 self.caller_owns_return = True 88 elif self.ret in ('char*', 'gchar*', 'string'): 89 self.caller_owns_return = True 90 else: 91 self.caller_owns_return = False 92 93 94class ObjectDef(Definition): 95 def __init__(self, name, *args): 96 self.name = name 97 self.module = None 98 self.parent = None 99 self.c_name = None 100 self.typecode = None 101 self.fields = [] 102 self.implements = [] 103 self.class_init_func = None 104 self.has_new_constructor_api = False 105 for arg in get_valid_scheme_definitions(args): 106 if arg[0] == 'in-module': 107 self.module = arg[1] 108 elif arg[0] == 'docstring': 109 self.docstring = make_docstring(arg[1:]) 110 elif arg[0] == 'parent': 111 self.parent = arg[1] 112 elif arg[0] == 'c-name': 113 self.c_name = arg[1] 114 elif arg[0] == 'gtype-id': 115 self.typecode = arg[1] 116 elif arg[0] == 'fields': 117 for parg in arg[1:]: 118 self.fields.append((parg[0], parg[1])) 119 elif arg[0] == 'implements': 120 self.implements.append(arg[1]) 121 def merge(self, old): 122 # currently the .h parser doesn't try to work out what fields of 123 # an object structure should be public, so we just copy the list 124 # from the old version ... 125 self.fields = old.fields 126 self.implements = old.implements 127 def write_defs(self, fp=sys.stdout): 128 fp.write('(define-object ' + self.name + '\n') 129 if self.module: 130 fp.write(' (in-module "' + self.module + '")\n') 131 if self.parent != (None, None): 132 fp.write(' (parent "' + self.parent + '")\n') 133 for interface in self.implements: 134 fp.write(' (implements "' + interface + '")\n') 135 if self.c_name: 136 fp.write(' (c-name "' + self.c_name + '")\n') 137 if self.typecode: 138 fp.write(' (gtype-id "' + self.typecode + '")\n') 139 if self.fields: 140 fp.write(' (fields\n') 141 for (ftype, fname) in self.fields: 142 fp.write(' \'("' + ftype + '" "' + fname + '")\n') 143 fp.write(' )\n') 144 fp.write(')\n\n') 145 146class InterfaceDef(Definition): 147 def __init__(self, name, *args): 148 self.name = name 149 self.module = None 150 self.c_name = None 151 self.typecode = None 152 self.vtable = None 153 self.fields = [] 154 self.interface_info = None 155 for arg in get_valid_scheme_definitions(args): 156 if arg[0] == 'in-module': 157 self.module = arg[1] 158 elif arg[0] == 'docstring': 159 self.docstring = make_docstring(arg[1:]) 160 elif arg[0] == 'c-name': 161 self.c_name = arg[1] 162 elif arg[0] == 'gtype-id': 163 self.typecode = arg[1] 164 elif arg[0] == 'vtable': 165 self.vtable = arg[1] 166 if self.vtable is None: 167 self.vtable = self.c_name + "Iface" 168 def write_defs(self, fp=sys.stdout): 169 fp.write('(define-interface ' + self.name + '\n') 170 if self.module: 171 fp.write(' (in-module "' + self.module + '")\n') 172 if self.c_name: 173 fp.write(' (c-name "' + self.c_name + '")\n') 174 if self.typecode: 175 fp.write(' (gtype-id "' + self.typecode + '")\n') 176 fp.write(')\n\n') 177 178class EnumDef(Definition): 179 def __init__(self, name, *args): 180 self.deftype = 'enum' 181 self.name = name 182 self.in_module = None 183 self.c_name = None 184 self.typecode = None 185 self.values = [] 186 for arg in get_valid_scheme_definitions(args): 187 if arg[0] == 'in-module': 188 self.in_module = arg[1] 189 elif arg[0] == 'c-name': 190 self.c_name = arg[1] 191 elif arg[0] == 'gtype-id': 192 self.typecode = arg[1] 193 elif arg[0] == 'values': 194 for varg in arg[1:]: 195 self.values.append((varg[0], varg[1])) 196 def merge(self, old): 197 pass 198 def write_defs(self, fp=sys.stdout): 199 fp.write('(define-' + self.deftype + ' ' + self.name + '\n') 200 if self.in_module: 201 fp.write(' (in-module "' + self.in_module + '")\n') 202 fp.write(' (c-name "' + self.c_name + '")\n') 203 fp.write(' (gtype-id "' + self.typecode + '")\n') 204 if self.values: 205 fp.write(' (values\n') 206 for name, val in self.values: 207 fp.write(' \'("' + name + '" "' + val + '")\n') 208 fp.write(' )\n') 209 fp.write(')\n\n') 210 211class FlagsDef(EnumDef): 212 def __init__(self, *args): 213 EnumDef.__init__(*(self,) + args) 214 self.deftype = 'flags' 215 216class BoxedDef(Definition): 217 def __init__(self, name, *args): 218 self.name = name 219 self.module = None 220 self.c_name = None 221 self.typecode = None 222 self.copy = None 223 self.release = None 224 self.fields = [] 225 for arg in get_valid_scheme_definitions(args): 226 if arg[0] == 'in-module': 227 self.module = arg[1] 228 elif arg[0] == 'c-name': 229 self.c_name = arg[1] 230 elif arg[0] == 'gtype-id': 231 self.typecode = arg[1] 232 elif arg[0] == 'copy-func': 233 self.copy = arg[1] 234 elif arg[0] == 'release-func': 235 self.release = arg[1] 236 elif arg[0] == 'fields': 237 for parg in arg[1:]: 238 self.fields.append((parg[0], parg[1])) 239 def merge(self, old): 240 # currently the .h parser doesn't try to work out what fields of 241 # an object structure should be public, so we just copy the list 242 # from the old version ... 243 self.fields = old.fields 244 def write_defs(self, fp=sys.stdout): 245 fp.write('(define-boxed ' + self.name + '\n') 246 if self.module: 247 fp.write(' (in-module "' + self.module + '")\n') 248 if self.c_name: 249 fp.write(' (c-name "' + self.c_name + '")\n') 250 if self.typecode: 251 fp.write(' (gtype-id "' + self.typecode + '")\n') 252 if self.copy: 253 fp.write(' (copy-func "' + self.copy + '")\n') 254 if self.release: 255 fp.write(' (release-func "' + self.release + '")\n') 256 if self.fields: 257 fp.write(' (fields\n') 258 for (ftype, fname) in self.fields: 259 fp.write(' \'("' + ftype + '" "' + fname + '")\n') 260 fp.write(' )\n') 261 fp.write(')\n\n') 262 263class PointerDef(Definition): 264 def __init__(self, name, *args): 265 self.name = name 266 self.module = None 267 self.c_name = None 268 self.typecode = None 269 self.fields = [] 270 for arg in get_valid_scheme_definitions(args): 271 if arg[0] == 'in-module': 272 self.module = arg[1] 273 elif arg[0] == 'c-name': 274 self.c_name = arg[1] 275 elif arg[0] == 'gtype-id': 276 self.typecode = arg[1] 277 elif arg[0] == 'fields': 278 for parg in arg[1:]: 279 self.fields.append((parg[0], parg[1])) 280 def merge(self, old): 281 # currently the .h parser doesn't try to work out what fields of 282 # an object structure should be public, so we just copy the list 283 # from the old version ... 284 self.fields = old.fields 285 def write_defs(self, fp=sys.stdout): 286 fp.write('(define-pointer ' + self.name + '\n') 287 if self.module: 288 fp.write(' (in-module "' + self.module + '")\n') 289 if self.c_name: 290 fp.write(' (c-name "' + self.c_name + '")\n') 291 if self.typecode: 292 fp.write(' (gtype-id "' + self.typecode + '")\n') 293 if self.fields: 294 fp.write(' (fields\n') 295 for (ftype, fname) in self.fields: 296 fp.write(' \'("' + ftype + '" "' + fname + '")\n') 297 fp.write(' )\n') 298 fp.write(')\n\n') 299 300class MethodDefBase(Definition): 301 def __init__(self, name, *args): 302 dump = 0 303 self.name = name 304 self.ret = None 305 self.caller_owns_return = None 306 self.unblock_threads = None 307 self.c_name = None 308 self.typecode = None 309 self.of_object = None 310 self.params = [] # of form (type, name, default, nullok) 311 self.varargs = 0 312 self.deprecated = None 313 for arg in get_valid_scheme_definitions(args): 314 if arg[0] == 'of-object': 315 self.of_object = arg[1] 316 elif arg[0] == 'docstring': 317 self.docstring = make_docstring(arg[1:]) 318 elif arg[0] == 'c-name': 319 self.c_name = arg[1] 320 elif arg[0] == 'gtype-id': 321 self.typecode = arg[1] 322 elif arg[0] == 'return-type': 323 type_name = arg[1] 324 optional = False 325 for prop in arg[2:]: 326 if prop[0] == 'optional': 327 optional = True 328 self.ret = ReturnType(type_name, optional) 329 elif arg[0] == 'caller-owns-return': 330 self.caller_owns_return = arg[1] in ('t', '#t') 331 elif arg[0] == 'unblock-threads': 332 self.unblock_threads = arg[1] in ('t', '#t') 333 elif arg[0] == 'parameters': 334 for parg in arg[1:]: 335 ptype = parg[0] 336 pname = parg[1] 337 pdflt = None 338 pnull = 0 339 pdir = None 340 for farg in parg[2:]: 341 assert isinstance(farg, tuple) 342 if farg[0] == 'default': 343 pdflt = farg[1] 344 elif farg[0] == 'null-ok': 345 pnull = 1 346 elif farg[0] == 'direction': 347 pdir = farg[1] 348 self.params.append(Parameter(ptype, pname, pdflt, pnull, pdir)) 349 elif arg[0] == 'varargs': 350 self.varargs = arg[1] in ('t', '#t') 351 elif arg[0] == 'deprecated': 352 self.deprecated = arg[1] 353 else: 354 sys.stderr.write("Warning: %s argument unsupported.\n" 355 % (arg[0])) 356 dump = 1 357 if dump: 358 self.write_defs(sys.stderr) 359 360 if self.caller_owns_return is None and self.ret is not None: 361 self.guess_return_value_ownership() 362 363 def merge(self, old, parmerge): 364 self.caller_owns_return = old.caller_owns_return 365 self.varargs = old.varargs 366 # here we merge extra parameter flags accross to the new object. 367 if not parmerge: 368 self.params = copy.deepcopy(old.params) 369 return 370 for i in range(len(self.params)): 371 ptype, pname, pdflt, pnull = self.params[i] 372 for p2 in old.params: 373 if p2[1] == pname: 374 self.params[i] = (ptype, pname, p2[2], p2[3]) 375 break 376 def _write_defs(self, fp=sys.stdout): 377 if self.of_object != (None, None): 378 fp.write(' (of-object "' + self.of_object + '")\n') 379 if self.c_name: 380 fp.write(' (c-name "' + self.c_name + '")\n') 381 if self.typecode: 382 fp.write(' (gtype-id "' + self.typecode + '")\n') 383 if self.caller_owns_return: 384 fp.write(' (caller-owns-return #t)\n') 385 if self.unblock_threads: 386 fp.write(' (unblock_threads #t)\n') 387 if self.ret: 388 fp.write(' (return-type "' + self.ret + '")\n') 389 if self.deprecated: 390 fp.write(' (deprecated "' + self.deprecated + '")\n') 391 if self.params: 392 fp.write(' (parameters\n') 393 for ptype, pname, pdflt, pnull in self.params: 394 fp.write(' \'("' + ptype + '" "' + pname +'"') 395 if pdflt: fp.write(' (default "' + pdflt + '")') 396 if pnull: fp.write(' (null-ok)') 397 fp.write(')\n') 398 fp.write(' )\n') 399 if self.varargs: 400 fp.write(' (varargs #t)\n') 401 fp.write(')\n\n') 402 403 404class MethodDef(MethodDefBase): 405 def __init__(self, name, *args): 406 MethodDefBase.__init__(self, name, *args) 407 for item in ('c_name', 'of_object'): 408 if self.__dict__[item] == None: 409 self.write_defs(sys.stderr) 410 raise RuntimeError("definition missing required %s" % (item,)) 411 412 def write_defs(self, fp=sys.stdout): 413 fp.write('(define-method ' + self.name + '\n') 414 self._write_defs(fp) 415 416class VirtualDef(MethodDefBase): 417 def write_defs(self, fp=sys.stdout): 418 fp.write('(define-virtual ' + self.name + '\n') 419 self._write_defs(fp) 420 421class FunctionDef(Definition): 422 def __init__(self, name, *args): 423 dump = 0 424 self.name = name 425 self.in_module = None 426 self.is_constructor_of = None 427 self.ret = None 428 self.caller_owns_return = None 429 self.unblock_threads = None 430 self.c_name = None 431 self.typecode = None 432 self.params = [] # of form (type, name, default, nullok) 433 self.varargs = 0 434 self.deprecated = None 435 for arg in get_valid_scheme_definitions(args): 436 if arg[0] == 'in-module': 437 self.in_module = arg[1] 438 elif arg[0] == 'docstring': 439 self.docstring = make_docstring(arg[1:]) 440 elif arg[0] == 'is-constructor-of': 441 self.is_constructor_of = arg[1] 442 elif arg[0] == 'c-name': 443 self.c_name = arg[1] 444 elif arg[0] == 'gtype-id': 445 self.typecode = arg[1] 446 elif arg[0] == 'return-type': 447 self.ret = arg[1] 448 elif arg[0] == 'caller-owns-return': 449 self.caller_owns_return = arg[1] in ('t', '#t') 450 elif arg[0] == 'unblock-threads': 451 self.unblock_threads = arg[1] in ('t', '#t') 452 elif arg[0] == 'parameters': 453 for parg in arg[1:]: 454 ptype = parg[0] 455 pname = parg[1] 456 pdflt = None 457 pnull = 0 458 for farg in parg[2:]: 459 if farg[0] == 'default': 460 pdflt = farg[1] 461 elif farg[0] == 'null-ok': 462 pnull = 1 463 self.params.append(Parameter(ptype, pname, pdflt, pnull)) 464 elif arg[0] == 'properties': 465 if self.is_constructor_of is None: 466 sys.stderr.write("Warning: (properties ...) "\ 467 "is only valid for constructors") 468 for prop in arg[1:]: 469 pname = prop[0] 470 optional = False 471 argname = pname 472 for farg in prop[1:]: 473 if farg[0] == 'optional': 474 optional = True 475 elif farg[0] == 'argname': 476 argname = farg[1] 477 self.params.append(Property(pname, optional, argname)) 478 elif arg[0] == 'varargs': 479 self.varargs = arg[1] in ('t', '#t') 480 elif arg[0] == 'deprecated': 481 self.deprecated = arg[1] 482 else: 483 sys.stderr.write("Warning: %s argument unsupported\n" 484 % (arg[0],)) 485 dump = 1 486 if dump: 487 self.write_defs(sys.stderr) 488 489 if self.caller_owns_return is None and self.ret is not None: 490 self.guess_return_value_ownership() 491 for item in ('c_name',): 492 if self.__dict__[item] == None: 493 self.write_defs(sys.stderr) 494 raise RuntimeError("definition missing required %s" % (item,)) 495 496 _method_write_defs = MethodDef.__dict__['write_defs'] 497 498 def merge(self, old, parmerge): 499 self.caller_owns_return = old.caller_owns_return 500 self.varargs = old.varargs 501 if not parmerge: 502 self.params = copy.deepcopy(old.params) 503 return 504 # here we merge extra parameter flags accross to the new object. 505 def merge_param(param): 506 for old_param in old.params: 507 if old_param.pname == param.pname: 508 if isinstance(old_param, Property): 509 # h2def never scans Property's, therefore if 510 # we have one it was manually written, so we 511 # keep it. 512 return copy.deepcopy(old_param) 513 else: 514 param.merge(old_param) 515 return param 516 raise RuntimeError("could not find %s in old_parameters %r" % ( 517 param.pname, [p.pname for p in old.params])) 518 try: 519 self.params = list(map(merge_param, self.params)) 520 except RuntimeError: 521 # parameter names changed and we can't find a match; it's 522 # safer to keep the old parameter list untouched. 523 self.params = copy.deepcopy(old.params) 524 525 if not self.is_constructor_of: 526 try: 527 self.is_constructor_of = old.is_constructor_of 528 except AttributeError: 529 pass 530 if isinstance(old, MethodDef): 531 self.name = old.name 532 # transmogrify from function into method ... 533 self.write_defs = self._method_write_defs 534 self.of_object = old.of_object 535 del self.params[0] 536 def write_defs(self, fp=sys.stdout): 537 fp.write('(define-function ' + self.name + '\n') 538 if self.in_module: 539 fp.write(' (in-module "' + self.in_module + '")\n') 540 if self.is_constructor_of: 541 fp.write(' (is-constructor-of "' + self.is_constructor_of +'")\n') 542 if self.c_name: 543 fp.write(' (c-name "' + self.c_name + '")\n') 544 if self.typecode: 545 fp.write(' (gtype-id "' + self.typecode + '")\n') 546 if self.caller_owns_return: 547 fp.write(' (caller-owns-return #t)\n') 548 if self.unblock_threads: 549 fp.write(' (unblock-threads #t)\n') 550 if self.ret: 551 fp.write(' (return-type "' + self.ret + '")\n') 552 if self.deprecated: 553 fp.write(' (deprecated "' + self.deprecated + '")\n') 554 if self.params: 555 if isinstance(self.params[0], Parameter): 556 fp.write(' (parameters\n') 557 for ptype, pname, pdflt, pnull in self.params: 558 fp.write(' \'("' + ptype + '" "' + pname +'"') 559 if pdflt: fp.write(' (default "' + pdflt + '")') 560 if pnull: fp.write(' (null-ok)') 561 fp.write(')\n') 562 fp.write(' )\n') 563 elif isinstance(self.params[0], Property): 564 fp.write(' (properties\n') 565 for prop in self.params: 566 fp.write(' \'("' + prop.pname +'"') 567 if prop.optional: fp.write(' (optional)') 568 fp.write(')\n') 569 fp.write(' )\n') 570 else: 571 assert False, "strange parameter list %r" % self.params[0] 572 if self.varargs: 573 fp.write(' (varargs #t)\n') 574 575 fp.write(')\n\n') 576