1 #!/usr/bin/env python 2 3 """ 4 Generate C code from object layouts and other deduced information. 5 6 Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 """ 21 22 from common import CommonOutput 23 from encoders import encode_bound_reference, encode_function_pointer, \ 24 encode_instantiator_pointer, \ 25 encode_literal_constant, encode_literal_constant_member, \ 26 encode_literal_constant_value, \ 27 encode_literal_instantiator, encode_literal_reference, \ 28 encode_path, \ 29 encode_predefined_reference, encode_size, \ 30 encode_symbol, encode_tablename, \ 31 encode_type_attribute 32 from os import listdir 33 from os.path import exists, isdir, join, split 34 from referencing import Reference 35 36 def copy(source, target): 37 38 "Copy a text file from 'source' to 'target'." 39 40 if isdir(target): 41 target = join(target, split(source)[-1]) 42 infile = open(source) 43 outfile = open(target, "w") 44 try: 45 outfile.write(infile.read()) 46 finally: 47 outfile.close() 48 infile.close() 49 50 class Generator(CommonOutput): 51 52 "A code generator." 53 54 function_type = "__builtins__.core.function" 55 56 # NOTE: These must be synchronised with the library. 57 58 predefined_constant_members = ( 59 ("__builtins__.boolean", "False"), 60 ("__builtins__.boolean", "True"), 61 ("__builtins__.none", "None"), 62 ("__builtins__.notimplemented", "NotImplemented"), 63 ) 64 65 literal_instantiator_types = ( 66 "__builtins__.dict.dict", 67 "__builtins__.list.list", 68 "__builtins__.tuple.tuple", 69 ) 70 71 def __init__(self, importer, optimiser, output): 72 self.importer = importer 73 self.optimiser = optimiser 74 self.output = output 75 76 def to_output(self, debug=False): 77 78 "Write the generated code." 79 80 self.check_output() 81 self.write_structures() 82 self.copy_templates(debug) 83 84 def copy_templates(self, debug=False): 85 86 "Copy template files to the generated output directory." 87 88 templates = join(split(__file__)[0], "templates") 89 90 for filename in listdir(templates): 91 target = self.output 92 93 # Handle debug resources. 94 95 if filename.endswith("-debug"): 96 if debug: 97 target = join(self.output, filename[:-len("-debug")]) 98 else: 99 continue 100 101 # Handle non-debug resources. 102 103 if debug and exists(join(templates, "%s-debug" % filename)): 104 continue 105 106 copy(join(templates, filename), target) 107 108 def write_structures(self): 109 110 "Write structures used by the program." 111 112 f_consts = open(join(self.output, "progconsts.h"), "w") 113 f_defs = open(join(self.output, "progtypes.c"), "w") 114 f_decls = open(join(self.output, "progtypes.h"), "w") 115 f_signatures = open(join(self.output, "main.h"), "w") 116 f_code = open(join(self.output, "main.c"), "w") 117 118 try: 119 # Output boilerplate. 120 121 print >>f_consts, """\ 122 #ifndef __PROGCONSTS_H__ 123 #define __PROGCONSTS_H__ 124 """ 125 print >>f_decls, """\ 126 #ifndef __PROGTYPES_H__ 127 #define __PROGTYPES_H__ 128 129 #include "progconsts.h" 130 #include "types.h" 131 """ 132 print >>f_defs, """\ 133 #include "progtypes.h" 134 #include "progops.h" 135 #include "main.h" 136 """ 137 print >>f_signatures, """\ 138 #ifndef __MAIN_H__ 139 #define __MAIN_H__ 140 141 #include "types.h" 142 """ 143 print >>f_code, """\ 144 #include <string.h> 145 #include <stdio.h> 146 #include "types.h" 147 #include "exceptions.h" 148 #include "ops.h" 149 #include "progconsts.h" 150 #include "progtypes.h" 151 #include "progops.h" 152 #include "main.h" 153 """ 154 155 # Generate table and structure data. 156 157 function_instance_attrs = None 158 objects = self.optimiser.attr_table.items() 159 objects.sort() 160 161 for ref, indexes in objects: 162 attrnames = self.get_attribute_names(indexes) 163 164 kind = ref.get_kind() 165 path = ref.get_origin() 166 table_name = encode_tablename(kind, path) 167 structure_size = encode_size(kind, path) 168 169 # Generate structures for classes and modules. 170 171 if kind != "<instance>": 172 structure = [] 173 attrs = self.get_static_attributes(kind, path, attrnames) 174 175 # Set a special instantiator on the class. 176 177 if kind == "<class>": 178 attrs["__fn__"] = path 179 attrs["__args__"] = encode_size("pmin", path) 180 181 # Write instantiator declarations based on the 182 # applicable initialiser. 183 184 init_ref = attrs["__init__"] 185 186 # Write instantiator definitions. 187 188 self.write_instantiator(f_code, f_signatures, path, init_ref) 189 190 # Write parameter table. 191 192 self.make_parameter_table(f_decls, f_defs, path, init_ref.get_origin()) 193 194 self.populate_structure(Reference(kind, path), attrs, kind, structure) 195 196 if kind == "<class>": 197 self.write_instance_structure(f_decls, path, structure_size) 198 199 self.write_structure(f_decls, f_defs, path, table_name, structure, 200 kind == "<class>" and path) 201 202 # Record function instance details for function generation below. 203 204 else: 205 attrs = self.get_instance_attributes(path, attrnames) 206 if path == self.function_type: 207 function_instance_attrs = attrs 208 209 # Write a table for all objects. 210 211 table = [] 212 self.populate_table(Reference(kind, path), table) 213 self.write_table(f_decls, f_defs, table_name, structure_size, table) 214 215 # Generate function instances. 216 217 functions = self.importer.function_parameters.keys() 218 functions.sort() 219 extra_function_instances = [] 220 221 for path in functions: 222 223 # Instantiators are generated above. 224 225 if self.importer.classes.has_key(path) or not self.importer.get_object(path): 226 continue 227 228 cls = self.function_type 229 table_name = encode_tablename("<instance>", cls) 230 structure_size = encode_size("<instance>", path) 231 232 # Set a special callable attribute on the instance. 233 234 function_instance_attrs["__fn__"] = path 235 function_instance_attrs["__args__"] = encode_size("pmin", path) 236 237 # Produce two structures where a method is involved. 238 239 parent, name = path.rsplit(".", 1) 240 parent_ref = self.importer.get_object(parent) 241 parent_kind = parent_ref and parent_ref.get_kind() 242 243 # Populate and write each structure. 244 245 if parent_kind == "<class>": 246 247 # A bound version of a method. 248 249 structure = self.populate_function(path, function_instance_attrs, False) 250 self.write_structure(f_decls, f_defs, encode_bound_reference(path), table_name, structure) 251 252 # An unbound version of a method. 253 254 structure = self.populate_function(path, function_instance_attrs, True) 255 self.write_structure(f_decls, f_defs, path, table_name, structure) 256 257 else: 258 # A normal function. 259 260 structure = self.populate_function(path, function_instance_attrs, False) 261 self.write_structure(f_decls, f_defs, path, table_name, structure) 262 263 # Functions with defaults need to declare instance structures. 264 265 if self.importer.function_defaults.get(path): 266 self.write_instance_structure(f_decls, path, structure_size) 267 extra_function_instances.append(path) 268 269 # Write function declarations. 270 # Signature: __attr <name>(__attr[]); 271 272 print >>f_signatures, "__attr %s(__attr args[]);" % encode_function_pointer(path) 273 274 # Write parameter table. 275 276 self.make_parameter_table(f_decls, f_defs, path, path) 277 278 # Generate predefined constants. 279 280 for path, name in self.predefined_constant_members: 281 self.make_predefined_constant(f_decls, f_defs, path, name) 282 283 # Generate literal constants. 284 285 for value, n in self.optimiser.constants.items(): 286 self.make_literal_constant(f_decls, f_defs, n, value) 287 288 # Finish the main source file. 289 290 self.write_main_program(f_code, f_signatures) 291 292 # Record size information for certain function instances as well as 293 # for classes, modules and other instances. 294 295 size_tables = {} 296 297 for kind in ["<class>", "<module>", "<instance>"]: 298 size_tables[kind] = {} 299 300 # Generate structure size data. 301 302 for ref, structure in self.optimiser.structures.items(): 303 size_tables[ref.get_kind()][ref.get_origin()] = len(structure) 304 305 for path in extra_function_instances: 306 defaults = self.importer.function_defaults[path] 307 size_tables["<instance>"][path] = size_tables["<instance>"][self.function_type] + len(defaults) 308 309 size_tables = size_tables.items() 310 size_tables.sort() 311 312 for kind, sizes in size_tables: 313 self.write_size_constants(f_consts, kind, sizes, 0) 314 315 # Generate parameter table size data. 316 317 min_sizes = {} 318 max_sizes = {} 319 320 for path, parameters in self.optimiser.parameters.items(): 321 argmin, argmax = self.get_argument_limits(path) 322 min_sizes[path] = argmin 323 max_sizes[path] = argmax 324 325 # Record instantiator limits. 326 327 if path.endswith(".__init__"): 328 path = path[:-len(".__init__")] 329 330 self.write_size_constants(f_consts, "pmin", min_sizes, 0) 331 self.write_size_constants(f_consts, "pmax", max_sizes, 0) 332 333 # Generate parameter codes. 334 335 self.write_code_constants(f_consts, self.optimiser.all_paramnames, self.optimiser.arg_locations, "pcode", "ppos") 336 337 # Generate attribute codes. 338 339 self.write_code_constants(f_consts, self.optimiser.all_attrnames, self.optimiser.locations, "code", "pos") 340 341 # Output more boilerplate. 342 343 print >>f_consts, """\ 344 345 #endif /* __PROGCONSTS_H__ */""" 346 347 print >>f_decls, """\ 348 349 #define __FUNCTION_TYPE %s 350 #define __FUNCTION_INSTANCE_SIZE %s 351 352 #endif /* __PROGTYPES_H__ */""" % ( 353 encode_path(self.function_type), 354 encode_size("<instance>", self.function_type) 355 ) 356 357 print >>f_signatures, """\ 358 359 #endif /* __MAIN_H__ */""" 360 361 finally: 362 f_consts.close() 363 f_defs.close() 364 f_decls.close() 365 f_signatures.close() 366 f_code.close() 367 368 def make_literal_constant(self, f_decls, f_defs, n, value): 369 370 """ 371 Write literal constant details to 'f_decls' (to declare a structure) and 372 to 'f_defs' (to define the contents) for the constant with the number 373 'n' with the given literal 'value'. 374 """ 375 376 const_path = encode_literal_constant(n) 377 structure_name = encode_literal_reference(n) 378 379 # NOTE: This makes assumptions about the __builtins__ structure. 380 381 modname = value.__class__.__name__ 382 typename = modname == "str" and "string" or modname 383 ref = Reference("<instance>", "__builtins__.%s.%s" % (modname, typename)) 384 385 self.make_constant(f_decls, f_defs, ref, const_path, structure_name, value) 386 387 def make_predefined_constant(self, f_decls, f_defs, path, name): 388 389 """ 390 Write predefined constant details to 'f_decls' (to declare a structure) 391 and to 'f_defs' (to define the contents) for the constant located in 392 'path' with the given 'name'. 393 """ 394 395 # Determine the details of the constant. 396 397 attr_path = "%s.%s" % (path, name) 398 structure_name = encode_predefined_reference(attr_path) 399 ref = self.importer.get_object(attr_path) 400 401 self.make_constant(f_decls, f_defs, ref, attr_path, structure_name) 402 403 def make_constant(self, f_decls, f_defs, ref, const_path, structure_name, data=None): 404 405 """ 406 Write constant details to 'f_decls' (to declare a structure) and to 407 'f_defs' (to define the contents) for the constant described by 'ref' 408 having the given 'path' and 'structure_name' (for the constant structure 409 itself). 410 """ 411 412 # Obtain the attributes. 413 414 cls = ref.get_origin() 415 indexes = self.optimiser.attr_table[ref] 416 attrnames = self.get_attribute_names(indexes) 417 attrs = self.get_instance_attributes(cls, attrnames) 418 419 # Set the data, if provided. 420 421 if data is not None: 422 attrs["__data__"] = data 423 424 # Define the structure details. An object is created for the constant, 425 # but an attribute is provided, referring to the object, for access to 426 # the constant in the program. 427 428 structure = [] 429 table_name = encode_tablename("<instance>", cls) 430 self.populate_structure(ref, attrs, ref.get_kind(), structure) 431 self.write_structure(f_decls, f_defs, structure_name, table_name, structure) 432 433 # Define a macro for the constant. 434 435 attr_name = encode_path(const_path) 436 print >>f_decls, "#define %s ((__attr) {&%s, &%s})" % (attr_name, structure_name, structure_name) 437 438 def make_parameter_table(self, f_decls, f_defs, path, function_path): 439 440 """ 441 Write parameter table details to 'f_decls' (to declare a table) and to 442 'f_defs' (to define the contents) for the function with the given 443 'path', using 'function_path' to obtain the parameter details. The 444 latter two arguments may differ when describing an instantiator using 445 the details of an initialiser. 446 """ 447 448 table = [] 449 table_name = encode_tablename("<function>", path) 450 structure_size = encode_size("pmax", path) 451 self.populate_parameter_table(function_path, table) 452 self.write_parameter_table(f_decls, f_defs, table_name, structure_size, table) 453 454 def write_size_constants(self, f_consts, size_prefix, sizes, padding): 455 456 """ 457 Write size constants to 'f_consts' for the given 'size_prefix', using 458 the 'sizes' dictionary to populate the definition, adding the given 459 'padding' to the basic sizes. 460 """ 461 462 print >>f_consts, "enum %s {" % encode_size(size_prefix) 463 first = True 464 for path, size in sizes.items(): 465 if not first: 466 print >>f_consts, "," 467 else: 468 first = False 469 f_consts.write(" %s = %d" % (encode_size(size_prefix, path), size + padding)) 470 print >>f_consts, "\n };" 471 472 def write_code_constants(self, f_consts, attrnames, locations, code_prefix, pos_prefix): 473 474 """ 475 Write code constants to 'f_consts' for the given 'attrnames' and 476 attribute 'locations'. 477 """ 478 479 print >>f_consts, "enum %s {" % encode_symbol(code_prefix) 480 first = True 481 for i, attrname in enumerate(attrnames): 482 if not first: 483 print >>f_consts, "," 484 else: 485 first = False 486 f_consts.write(" %s = %d" % (encode_symbol(code_prefix, attrname), i)) 487 print >>f_consts, "\n };" 488 489 print >>f_consts, "enum %s {" % encode_symbol(pos_prefix) 490 first = True 491 for i, attrnames in enumerate(locations): 492 for attrname in attrnames: 493 if not first: 494 print >>f_consts, "," 495 else: 496 first = False 497 f_consts.write(" %s = %d" % (encode_symbol(pos_prefix, attrname), i)) 498 print >>f_consts, "\n };" 499 500 def write_table(self, f_decls, f_defs, table_name, structure_size, table): 501 502 """ 503 Write the declarations to 'f_decls' and definitions to 'f_defs' for 504 the object having the given 'table_name' and the given 'structure_size', 505 with 'table' details used to populate the definition. 506 """ 507 508 print >>f_decls, "extern const __table %s;\n" % table_name 509 510 # Write the corresponding definition. 511 512 print >>f_defs, "const __table %s = {\n %s,\n {\n %s\n }\n };\n" % ( 513 table_name, structure_size, 514 ",\n ".join(table)) 515 516 def write_parameter_table(self, f_decls, f_defs, table_name, structure_size, table): 517 518 """ 519 Write the declarations to 'f_decls' and definitions to 'f_defs' for 520 the object having the given 'table_name' and the given 'structure_size', 521 with 'table' details used to populate the definition. 522 """ 523 524 print >>f_decls, "extern const __ptable %s;\n" % table_name 525 526 # Write the corresponding definition. 527 528 print >>f_defs, "const __ptable %s = {\n %s,\n {\n %s\n }\n };\n" % ( 529 table_name, structure_size, 530 ",\n ".join([("{%s, %s}" % t) for t in table])) 531 532 def write_instance_structure(self, f_decls, path, structure_size): 533 534 """ 535 Write a declaration to 'f_decls' for the object having the given 'path' 536 and the given 'structure_size'. 537 """ 538 539 # Write an instance-specific type definition for instances of classes. 540 # See: templates/types.h 541 542 print >>f_decls, """\ 543 typedef struct { 544 const __table * table; 545 unsigned int pos; 546 __attr attrs[%s]; 547 } %s; 548 """ % (structure_size, encode_symbol("obj", path)) 549 550 def write_structure(self, f_decls, f_defs, structure_name, table_name, structure, path=None): 551 552 """ 553 Write the declarations to 'f_decls' and definitions to 'f_defs' for 554 the object having the given 'structure_name', the given 'table_name', 555 and the given 'structure' details used to populate the definition. 556 """ 557 558 if f_decls: 559 print >>f_decls, "extern __obj %s;\n" % encode_path(structure_name) 560 561 is_class = path and self.importer.get_object(path).has_kind("<class>") 562 pos = is_class and encode_symbol("pos", encode_type_attribute(path)) or "0" 563 564 print >>f_defs, """\ 565 __obj %s = { 566 &%s, 567 %s, 568 { 569 %s 570 }}; 571 """ % ( 572 encode_path(structure_name), table_name, pos, 573 ",\n ".join(structure)) 574 575 def get_argument_limits(self, path): 576 577 """ 578 Return the argument minimum and maximum for the callable at 'path', 579 adding an argument position for a universal context. 580 """ 581 582 parameters = self.importer.function_parameters[path] 583 defaults = self.importer.function_defaults.get(path) 584 num_parameters = len(parameters) + 1 585 return num_parameters - (defaults and len(defaults) or 0), num_parameters 586 587 def get_attribute_names(self, indexes): 588 589 """ 590 Given a list of attribute table 'indexes', return a list of attribute 591 names. 592 """ 593 594 all_attrnames = self.optimiser.all_attrnames 595 attrnames = [] 596 for i in indexes: 597 if i is None: 598 attrnames.append(None) 599 else: 600 attrnames.append(all_attrnames[i]) 601 return attrnames 602 603 def get_static_attributes(self, kind, name, attrnames): 604 605 """ 606 Return a mapping of attribute names to paths for attributes belonging 607 to objects of the given 'kind' (being "<class>" or "<module>") with 608 the given 'name' and supporting the given 'attrnames'. 609 """ 610 611 attrs = {} 612 613 for attrname in attrnames: 614 if attrname is None: 615 continue 616 if kind == "<class>": 617 path = self.importer.all_class_attrs[name][attrname] 618 elif kind == "<module>": 619 path = "%s.%s" % (name, attrname) 620 else: 621 continue 622 623 # The module may be hidden. 624 625 attr = self.importer.get_object(path) 626 if not attr: 627 module = self.importer.hidden.get(path) 628 if module: 629 attr = Reference(module.name, "<module>") 630 attrs[attrname] = attr 631 632 return attrs 633 634 def get_instance_attributes(self, name, attrnames): 635 636 """ 637 Return a mapping of attribute names to references for attributes 638 belonging to instances of the class with the given 'name', where the 639 given 'attrnames' are supported. 640 """ 641 642 consts = self.importer.all_instance_attr_constants[name] 643 attrs = {} 644 for attrname in attrnames: 645 if attrname is None: 646 continue 647 const = consts.get(attrname) 648 attrs[attrname] = const or Reference("<var>", "%s.%s" % (name, attrname)) 649 return attrs 650 651 def populate_table(self, key, table): 652 653 """ 654 Traverse the attributes in the determined order for the structure having 655 the given 'key', adding entries to the attribute 'table'. 656 """ 657 658 for attrname in self.optimiser.structures[key]: 659 660 # Handle gaps in the structure. 661 662 if attrname is None: 663 table.append("0") 664 else: 665 table.append(encode_symbol("code", attrname)) 666 667 def populate_parameter_table(self, key, table): 668 669 """ 670 Traverse the parameters in the determined order for the structure having 671 the given 'key', adding entries to the attribute 'table'. 672 """ 673 674 for value in self.optimiser.parameters[key]: 675 676 # Handle gaps in the structure. 677 678 if value is None: 679 table.append(("0", "0")) 680 else: 681 name, pos = value 682 table.append((encode_symbol("pcode", name), pos)) 683 684 def populate_function(self, path, function_instance_attrs, unbound=False): 685 686 """ 687 Populate a structure for the function with the given 'path'. The given 688 'attrs' provide the instance attributes, and if 'unbound' is set to a 689 true value, an unbound method structure is produced (as opposed to a 690 callable bound method structure). 691 """ 692 693 structure = [] 694 self.populate_structure(Reference("<function>", path), function_instance_attrs, "<instance>", structure, unbound) 695 696 # Append default members. 697 698 self.append_defaults(path, structure) 699 return structure 700 701 def populate_structure(self, ref, attrs, kind, structure, unbound=False): 702 703 """ 704 Traverse the attributes in the determined order for the structure having 705 the given 'ref' whose members are provided by the 'attrs' mapping, in a 706 structure of the given 'kind', adding entries to the object 'structure'. 707 If 'unbound' is set to a true value, an unbound method function pointer 708 will be employed, with a reference to the bound method incorporated into 709 the special __fn__ attribute. 710 """ 711 712 # Populate function instance structures for functions. 713 714 if ref.has_kind("<function>"): 715 origin = self.function_type 716 structure_ref = Reference("<instance>", self.function_type) 717 718 # Otherwise, just populate the appropriate structures. 719 720 else: 721 origin = ref.get_origin() 722 structure_ref = ref 723 724 # Refer to instantiator function tables for classes, specific function 725 # tables for individual functions. 726 727 ptable = encode_tablename("<function>", ref.get_origin()) 728 729 for attrname in self.optimiser.structures[structure_ref]: 730 731 # Handle gaps in the structure. 732 733 if attrname is None: 734 structure.append("{0, 0}") 735 736 # Handle non-constant and constant members. 737 738 else: 739 attr = attrs[attrname] 740 741 # Special function pointer member. 742 743 if attrname == "__fn__": 744 745 # Provide bound method references and the unbound function 746 # pointer if populating methods in a class. 747 748 bound_attr = None 749 750 # Classes offer instantiators. 751 752 if kind == "<class>": 753 attr = encode_instantiator_pointer(attr) 754 755 # Methods offers references to bound versions and an unbound 756 # method function. 757 758 elif unbound: 759 bound_attr = encode_bound_reference(attr) 760 attr = "__unbound_method" 761 762 # Other functions just offer function pointers. 763 764 else: 765 attr = encode_function_pointer(attr) 766 767 structure.append("{%s, .fn=%s}" % (bound_attr and ".b=&%s" % bound_attr or "0", attr)) 768 continue 769 770 # Special argument specification member. 771 772 elif attrname == "__args__": 773 structure.append("{.min=%s, .ptable=&%s}" % (attr, ptable)) 774 continue 775 776 # Special internal data member. 777 778 elif attrname == "__data__": 779 structure.append("{0, .%s=%s}" % (encode_literal_constant_member(attr), 780 encode_literal_constant_value(attr))) 781 continue 782 783 structure.append(self.encode_member(origin, attrname, attr, kind)) 784 785 def encode_member(self, path, name, ref, structure_type): 786 787 """ 788 Encode within the structure provided by 'path', the member whose 'name' 789 provides 'ref', within the given 'structure_type'. 790 """ 791 792 kind = ref.get_kind() 793 origin = ref.get_origin() 794 795 # References to constant literals. 796 797 if kind == "<instance>": 798 attr_path = "%s.%s" % (path, name) 799 800 # Obtain a constant value directly assigned to the attribute. 801 802 if self.optimiser.constant_numbers.has_key(attr_path): 803 constant_number = self.optimiser.constant_numbers[attr_path] 804 constant_value = "const%d" % constant_number 805 return "{&%s, &%s} /* %s */" % (constant_value, constant_value, name) 806 807 # Predefined constant references. 808 809 if (path, name) in self.predefined_constant_members: 810 attr_path = encode_predefined_reference("%s.%s" % (path, name)) 811 return "{&%s, &%s} /* %s */" % (attr_path, attr_path, name) 812 813 # General undetermined members. 814 815 if kind in ("<var>", "<instance>"): 816 return "{0, 0} /* %s */" % name 817 818 # Set the context depending on the kind of attribute. 819 # For methods: {&<parent>, &<attr>} 820 # For other attributes: {&<attr>, &<attr>} 821 822 else: 823 if kind == "<function>" and structure_type == "<class>": 824 parent = origin.rsplit(".", 1)[0] 825 context = "&%s" % encode_path(parent) 826 elif kind == "<instance>": 827 context = "&%s" % encode_path(origin) 828 else: 829 context = "0" 830 return "{%s, &%s}" % (context, encode_path(origin)) 831 832 def append_defaults(self, path, structure): 833 834 """ 835 For the given 'path', append default parameter members to the given 836 'structure'. 837 """ 838 839 for name, default in self.importer.function_defaults.get(path): 840 structure.append(self.encode_member(path, name, default, "<instance>")) 841 842 def write_instantiator(self, f_code, f_signatures, path, init_ref): 843 844 """ 845 Write an instantiator to 'f_code', with a signature to 'f_signatures', 846 for instances of the class with the given 'path', with 'init_ref' as the 847 initialiser function reference. 848 849 NOTE: This also needs to initialise any __fn__ and __args__ members 850 NOTE: where __call__ is provided by the class. 851 """ 852 853 parameters = self.importer.function_parameters[init_ref.get_origin()] 854 855 print >>f_code, """\ 856 __attr %s(__attr __args[]) 857 { 858 /* Allocate the structure. */ 859 __args[0] = __new(&%s, &%s, sizeof(%s)); 860 861 /* Call the initialiser. */ 862 %s(__args); 863 864 /* Return the allocated object details. */ 865 return __args[0]; 866 } 867 """ % ( 868 encode_instantiator_pointer(path), 869 encode_tablename("<instance>", path), 870 encode_path(path), 871 encode_symbol("obj", path), 872 encode_function_pointer(init_ref.get_origin()) 873 ) 874 875 print >>f_signatures, "__attr %s(__attr[]);" % encode_instantiator_pointer(path) 876 877 # Write additional literal instantiators. These do not call the 878 # initialisers but instead populate the structures directly. 879 880 if path in self.literal_instantiator_types: 881 print >>f_code, """\ 882 __attr %s(__attr __args[], unsigned int number) 883 { 884 __attr data; 885 886 /* Allocate the structure. */ 887 __args[0] = __new(&%s, &%s, sizeof(%s)); 888 889 /* Allocate a structure for the data. */ 890 data = __newdata(__args, number); 891 892 /* Store a reference to the data in the object's __data__ attribute. */ 893 __store_via_object(__args[0].value, %s, data); 894 895 /* Return the allocated object details. */ 896 return __args[0]; 897 } 898 """ % ( 899 encode_literal_instantiator(path), 900 encode_tablename("<instance>", path), 901 encode_path(path), 902 encode_symbol("obj", path), 903 encode_symbol("pos", "__data__") 904 ) 905 906 print >>f_signatures, "__attr %s(__attr[], unsigned int);" % encode_literal_instantiator(path) 907 908 def write_main_program(self, f_code, f_signatures): 909 910 """ 911 Write the main program to 'f_code', invoking the program's modules. Also 912 write declarations for module main functions to 'f_signatures'. 913 """ 914 915 print >>f_code, """\ 916 int main(int argc, char *argv[]) 917 { 918 __exc __tmp_exc; 919 __Try 920 {""" 921 922 for name in self.importer.order_modules(): 923 function_name = "__main_%s" % encode_path(name) 924 print >>f_signatures, "void %s();" % function_name 925 926 # Omit the native module. 927 928 if name != "native": 929 print >>f_code, """\ 930 %s();""" % function_name 931 932 print >>f_code, """\ 933 return 0; 934 } 935 __Catch(__tmp_exc) 936 { 937 fprintf(stderr, "Program terminated due to exception.\\n"); 938 return 1; 939 } 940 } 941 """ 942 943 # vim: tabstop=4 expandtab shiftwidth=4