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 = self.importer.function_parameters.keys() 260 functions.sort() 261 262 for path in functions: 263 264 # Instantiators are generated above. 265 266 if self.importer.classes.has_key(path) or not self.importer.get_object(path): 267 continue 268 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 parent, name = path.rsplit(".", 1) 281 parent_ref = self.importer.get_object(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 modname = value.__class__.__name__ 373 typename = modname == "str" and "string" or modname 374 ref = Reference("<instance>", "__builtins__.%s.%s" % (modname, typename)) 375 376 self.make_constant(f_decls, f_defs, ref, const_path, structure_name, value) 377 378 def make_predefined_constant(self, f_decls, f_defs, path, name): 379 380 """ 381 Write predefined constant details to 'f_decls' (to declare a structure) 382 and to 'f_defs' (to define the contents) for the constant located in 383 'path' with the given 'name'. 384 """ 385 386 # Determine the details of the constant. 387 388 attr_path = "%s.%s" % (path, name) 389 structure_name = encode_predefined_reference(attr_path) 390 ref = self.importer.get_object(attr_path) 391 392 self.make_constant(f_decls, f_defs, ref, attr_path, structure_name) 393 394 def make_constant(self, f_decls, f_defs, ref, const_path, structure_name, data=None): 395 396 """ 397 Write constant details to 'f_decls' (to declare a structure) and to 398 'f_defs' (to define the contents) for the constant described by 'ref' 399 having the given 'path' and 'structure_name' (for the constant structure 400 itself). 401 """ 402 403 # Obtain the attributes. 404 405 cls = ref.get_origin() 406 indexes = self.optimiser.attr_table[ref] 407 attrnames = self.get_attribute_names(indexes) 408 attrs = self.get_instance_attributes(cls, attrnames) 409 410 # Set the data, if provided. 411 412 if data is not None: 413 attrs["__data__"] = data 414 415 # Define the structure details. An object is created for the constant, 416 # but an attribute is provided, referring to the object, for access to 417 # the constant in the program. 418 419 structure = [] 420 table_name = encode_tablename("<instance>", cls) 421 structure_size = encode_size("<instance>", cls) 422 self.populate_structure(ref, attrs, ref.get_kind(), structure) 423 self.write_structure(f_decls, f_defs, structure_name, table_name, structure_size, structure) 424 425 # Define a macro for the constant. 426 427 attr_name = encode_path(const_path) 428 print >>f_decls, "#define %s ((__attr) {&%s, &%s})" % (attr_name, structure_name, structure_name) 429 430 def make_parameter_table(self, f_decls, f_defs, path, function_path): 431 432 """ 433 Write parameter table details to 'f_decls' (to declare a table) and to 434 'f_defs' (to define the contents) for the function with the given 435 'path', using 'function_path' to obtain the parameter details. The 436 latter two arguments may differ when describing an instantiator using 437 the details of an initialiser. 438 """ 439 440 table = [] 441 table_name = encode_tablename("<function>", path) 442 structure_size = encode_size("pmax", path) 443 self.populate_parameter_table(function_path, table) 444 self.write_parameter_table(f_decls, f_defs, table_name, structure_size, table) 445 446 def write_size_constants(self, f_consts, size_prefix, sizes, padding): 447 448 """ 449 Write size constants to 'f_consts' for the given 'size_prefix', using 450 the 'sizes' dictionary to populate the definition, adding the given 451 'padding' to the basic sizes. 452 """ 453 454 print >>f_consts, "enum %s {" % encode_size(size_prefix) 455 first = True 456 for path, size in sizes.items(): 457 if not first: 458 print >>f_consts, "," 459 else: 460 first = False 461 f_consts.write(" %s = %d" % (encode_size(size_prefix, path), size + padding)) 462 print >>f_consts, "\n };" 463 464 def write_code_constants(self, f_consts, attrnames, locations, code_prefix, pos_prefix): 465 466 """ 467 Write code constants to 'f_consts' for the given 'attrnames' and 468 attribute 'locations'. 469 """ 470 471 print >>f_consts, "enum %s {" % encode_symbol(code_prefix) 472 first = True 473 for i, attrname in enumerate(attrnames): 474 if not first: 475 print >>f_consts, "," 476 else: 477 first = False 478 f_consts.write(" %s = %d" % (encode_symbol(code_prefix, attrname), i)) 479 print >>f_consts, "\n };" 480 481 print >>f_consts, "enum %s {" % encode_symbol(pos_prefix) 482 first = True 483 for i, attrnames in enumerate(locations): 484 for attrname in attrnames: 485 if not first: 486 print >>f_consts, "," 487 else: 488 first = False 489 f_consts.write(" %s = %d" % (encode_symbol(pos_prefix, attrname), i)) 490 print >>f_consts, "\n };" 491 492 def write_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 __table %s;\n" % table_name 501 502 # Write the corresponding definition. 503 504 print >>f_defs, "const __table %s = {\n %s,\n {\n %s\n }\n };\n" % ( 505 table_name, structure_size, 506 ",\n ".join(table)) 507 508 def write_parameter_table(self, f_decls, f_defs, table_name, structure_size, table): 509 510 """ 511 Write the declarations to 'f_decls' and definitions to 'f_defs' for 512 the object having the given 'table_name' and the given 'structure_size', 513 with 'table' details used to populate the definition. 514 """ 515 516 print >>f_decls, "extern const __ptable %s;\n" % table_name 517 518 # Write the corresponding definition. 519 520 print >>f_defs, "const __ptable %s = {\n %s,\n {\n %s\n }\n };\n" % ( 521 table_name, structure_size, 522 ",\n ".join([("{%s, %s}" % t) for t in table])) 523 524 def write_instance_structure(self, f_decls, path, structure_size): 525 526 """ 527 Write a declaration to 'f_decls' for the object having the given 'path' 528 and the given 'structure_size'. 529 """ 530 531 # Write an instance-specific type definition for instances of classes. 532 # See: templates/types.h 533 534 print >>f_decls, """\ 535 typedef struct { 536 const __table * table; 537 unsigned int pos; 538 __attr attrs[%s]; 539 } %s; 540 """ % (structure_size, encode_symbol("obj", path)) 541 542 def write_structure(self, f_decls, f_defs, structure_name, table_name, structure_size, structure, path=None): 543 544 """ 545 Write the declarations to 'f_decls' and definitions to 'f_defs' for 546 the object having the given 'structure_name', the given 'table_name', 547 and the given 'structure_size', with 'structure' details used to 548 populate the definition. 549 """ 550 551 if f_decls: 552 print >>f_decls, "extern __obj %s;\n" % encode_path(structure_name) 553 554 is_class = path and self.importer.get_object(path).has_kind("<class>") 555 pos = is_class and encode_symbol("pos", encode_type_attribute(path)) or "0" 556 557 print >>f_defs, """\ 558 __obj %s = { 559 &%s, 560 %s, 561 { 562 %s 563 }}; 564 """ % ( 565 encode_path(structure_name), table_name, pos, 566 ",\n ".join(structure)) 567 568 def get_argument_limits(self, path): 569 570 """ 571 Return the argument minimum and maximum for the callable at 'path', 572 adding an argument position for a universal context. 573 """ 574 575 parameters = self.importer.function_parameters[path] 576 defaults = self.importer.function_defaults.get(path) 577 num_parameters = len(parameters) + 1 578 return num_parameters - (defaults and len(defaults) or 0), num_parameters 579 580 def get_attribute_names(self, indexes): 581 582 """ 583 Given a list of attribute table 'indexes', return a list of attribute 584 names. 585 """ 586 587 all_attrnames = self.optimiser.all_attrnames 588 attrnames = [] 589 for i in indexes: 590 if i is None: 591 attrnames.append(None) 592 else: 593 attrnames.append(all_attrnames[i]) 594 return attrnames 595 596 def get_static_attributes(self, kind, name, attrnames): 597 598 """ 599 Return a mapping of attribute names to paths for attributes belonging 600 to objects of the given 'kind' (being "<class>" or "<module>") with 601 the given 'name' and supporting the given 'attrnames'. 602 """ 603 604 attrs = {} 605 606 for attrname in attrnames: 607 if attrname is None: 608 continue 609 if kind == "<class>": 610 path = self.importer.all_class_attrs[name][attrname] 611 elif kind == "<module>": 612 path = "%s.%s" % (name, attrname) 613 else: 614 continue 615 616 # The module may be hidden. 617 618 attr = self.importer.get_object(path) 619 if not attr: 620 module = self.importer.hidden.get(path) 621 if module: 622 attr = Reference(module.name, "<module>") 623 attrs[attrname] = attr 624 625 return attrs 626 627 def get_instance_attributes(self, name, attrnames): 628 629 """ 630 Return a mapping of attribute names to references for attributes 631 belonging to instances of the class with the given 'name', where the 632 given 'attrnames' are supported. 633 """ 634 635 consts = self.importer.all_instance_attr_constants[name] 636 attrs = {} 637 for attrname in attrnames: 638 if attrname is None: 639 continue 640 const = consts.get(attrname) 641 attrs[attrname] = const or Reference("<var>", "%s.%s" % (name, attrname)) 642 return attrs 643 644 def populate_table(self, key, table): 645 646 """ 647 Traverse the attributes in the determined order for the structure having 648 the given 'key', adding entries to the attribute 'table'. 649 """ 650 651 for attrname in self.optimiser.structures[key]: 652 653 # Handle gaps in the structure. 654 655 if attrname is None: 656 table.append("0") 657 else: 658 table.append(encode_symbol("code", attrname)) 659 660 def populate_parameter_table(self, key, table): 661 662 """ 663 Traverse the parameters in the determined order for the structure having 664 the given 'key', adding entries to the attribute 'table'. 665 """ 666 667 for value in self.optimiser.parameters[key]: 668 669 # Handle gaps in the structure. 670 671 if value is None: 672 table.append(("0", "0")) 673 else: 674 name, pos = value 675 table.append((encode_symbol("pcode", name), pos)) 676 677 def populate_function(self, path, function_instance_attrs, unbound=False): 678 679 """ 680 Populate a structure for the function with the given 'path'. The given 681 'attrs' provide the instance attributes, and if 'unbound' is set to a 682 true value, an unbound method structure is produced (as opposed to a 683 callable bound method structure). 684 """ 685 686 structure = [] 687 self.populate_structure(Reference("<function>", path), function_instance_attrs, "<instance>", structure, unbound) 688 689 # Append default members. 690 691 self.append_defaults(path, structure) 692 return structure 693 694 def populate_structure(self, ref, attrs, kind, structure, unbound=False): 695 696 """ 697 Traverse the attributes in the determined order for the structure having 698 the given 'ref' whose members are provided by the 'attrs' mapping, in a 699 structure of the given 'kind', adding entries to the object 'structure'. 700 If 'unbound' is set to a true value, an unbound method function pointer 701 will be employed, with a reference to the bound method incorporated into 702 the special __fn__ attribute. 703 """ 704 705 # Populate function instance structures for functions. 706 707 if ref.has_kind("<function>"): 708 origin = self.function_type 709 structure_ref = Reference("<instance>", self.function_type) 710 711 # Otherwise, just populate the appropriate structures. 712 713 else: 714 origin = ref.get_origin() 715 structure_ref = ref 716 717 # Refer to instantiator function tables for classes, specific function 718 # tables for individual functions. 719 720 ptable = encode_tablename("<function>", ref.get_origin()) 721 722 for attrname in self.optimiser.structures[structure_ref]: 723 724 # Handle gaps in the structure. 725 726 if attrname is None: 727 structure.append("{0, 0}") 728 729 # Handle non-constant and constant members. 730 731 else: 732 attr = attrs[attrname] 733 734 # Special function pointer member. 735 736 if attrname == "__fn__": 737 738 # Provide bound method references and the unbound function 739 # pointer if populating methods in a class. 740 741 bound_attr = None 742 743 # Classes offer instantiators. 744 745 if kind == "<class>": 746 attr = encode_instantiator_pointer(attr) 747 748 # Methods offers references to bound versions and an unbound 749 # method function. 750 751 elif unbound: 752 bound_attr = encode_bound_reference(attr) 753 attr = "__unbound_method" 754 755 # Other functions just offer function pointers. 756 757 else: 758 attr = encode_function_pointer(attr) 759 760 structure.append("{%s, .fn=%s}" % (bound_attr and ".b=&%s" % bound_attr or "0", attr)) 761 continue 762 763 # Special argument specification member. 764 765 elif attrname == "__args__": 766 structure.append("{.min=%s, .ptable=&%s}" % (attr, ptable)) 767 continue 768 769 # Special internal data member. 770 771 elif attrname == "__data__": 772 structure.append("{0, .%s=%s}" % (encode_literal_constant_member(attr), 773 encode_literal_constant_value(attr))) 774 continue 775 776 structure.append(self.encode_member(origin, attrname, attr, kind)) 777 778 def encode_member(self, path, name, ref, structure_type): 779 780 """ 781 Encode within the structure provided by 'path', the member whose 'name' 782 provides 'ref', within the given 'structure_type'. 783 """ 784 785 kind = ref.get_kind() 786 origin = ref.get_origin() 787 788 # References to constant literals. 789 790 if kind == "<instance>": 791 attr_path = "%s.%s" % (path, name) 792 793 # Obtain a constant value directly assigned to the attribute. 794 795 if self.optimiser.constant_numbers.has_key(attr_path): 796 constant_number = self.optimiser.constant_numbers[attr_path] 797 constant_value = "const%d" % constant_number 798 return "{&%s, &%s} /* %s */" % (constant_value, constant_value, name) 799 800 # Predefined constant references. 801 802 if (path, name) in self.predefined_constant_members: 803 attr_path = encode_predefined_reference("%s.%s" % (path, name)) 804 return "{&%s, &%s} /* %s */" % (attr_path, attr_path, name) 805 806 # General undetermined members. 807 808 if kind in ("<var>", "<instance>"): 809 return "{0, 0} /* %s */" % name 810 811 # Set the context depending on the kind of attribute. 812 # For methods: {&<parent>, &<attr>} 813 # For other attributes: {&<attr>, &<attr>} 814 815 else: 816 if kind == "<function>" and structure_type == "<class>": 817 parent = origin.rsplit(".", 1)[0] 818 context = "&%s" % encode_path(parent) 819 elif kind == "<instance>": 820 context = "&%s" % encode_path(origin) 821 else: 822 context = "0" 823 return "{%s, &%s}" % (context, encode_path(origin)) 824 825 def append_defaults(self, path, structure): 826 827 """ 828 For the given 'path', append default parameter members to the given 829 'structure'. 830 """ 831 832 for name, default in self.importer.function_defaults.get(path): 833 structure.append(self.encode_member(path, name, default, "<instance>")) 834 835 def write_instantiator(self, f_code, f_signatures, path, init_ref): 836 837 """ 838 Write an instantiator to 'f_code', with a signature to 'f_signatures', 839 for instances of the class with the given 'path', with 'init_ref' as the 840 initialiser function reference. 841 842 NOTE: This also needs to initialise any __fn__ and __args__ members 843 NOTE: where __call__ is provided by the class. 844 """ 845 846 parameters = self.importer.function_parameters[init_ref.get_origin()] 847 848 print >>f_code, """\ 849 __attr %s(__attr __args[]) 850 { 851 /* Allocate the structure. */ 852 __args[0] = __new(&%s, &%s, sizeof(%s)); 853 854 /* Call the initialiser. */ 855 %s(__args); 856 857 /* Return the allocated object details. */ 858 return __args[0]; 859 } 860 """ % ( 861 encode_instantiator_pointer(path), 862 encode_tablename("<instance>", path), 863 encode_path(path), 864 encode_symbol("obj", path), 865 encode_function_pointer(init_ref.get_origin()) 866 ) 867 868 print >>f_signatures, "__attr %s(__attr[]);" % encode_instantiator_pointer(path) 869 870 # Write additional literal instantiators. These do not call the 871 # initialisers but instead populate the structures directly. 872 873 if path in self.literal_instantiator_types: 874 print >>f_code, """\ 875 __attr %s(__attr __args[], unsigned int number) 876 { 877 __attr data; 878 879 /* Allocate the structure. */ 880 __args[0] = __new(&%s, &%s, sizeof(%s)); 881 882 /* Allocate a structure for the data. */ 883 data = __newdata(__args, number); 884 885 /* Store a reference to the data in the object's __data__ attribute. */ 886 __store_via_object(__args[0].value, %s, data); 887 888 /* Return the allocated object details. */ 889 return __args[0]; 890 } 891 """ % ( 892 encode_literal_instantiator(path), 893 encode_tablename("<instance>", path), 894 encode_path(path), 895 encode_symbol("obj", path), 896 encode_symbol("pos", "__data__") 897 ) 898 899 print >>f_signatures, "__attr %s(__attr[], unsigned int);" % encode_literal_instantiator(path) 900 901 def write_main_program(self, f_code, f_signatures): 902 903 """ 904 Write the main program to 'f_code', invoking the program's modules. Also 905 write declarations for module main functions to 'f_signatures'. 906 """ 907 908 print >>f_code, """\ 909 int main(int argc, char *argv[]) 910 { 911 __exc __tmp_exc; 912 __Try 913 {""" 914 915 for name in self.importer.order_modules(): 916 function_name = "__main_%s" % encode_path(name) 917 print >>f_signatures, "void %s();" % function_name 918 919 # Omit the native module. 920 921 if name != "native": 922 print >>f_code, """\ 923 %s();""" % function_name 924 925 print >>f_code, """\ 926 return 0; 927 } 928 __Catch(__tmp_exc) 929 { 930 fprintf(stderr, "Program terminated due to exception.\\n"); 931 return 1; 932 } 933 } 934 """ 935 936 # vim: tabstop=4 expandtab shiftwidth=4