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