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