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