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