1 #!/usr/bin/env python 2 3 """ 4 Generate C code from object layouts and other deduced information. 5 6 Copyright (C) 2015, 2016, 2017 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, copy 23 from encoders import encode_code, \ 24 encode_function_pointer, \ 25 encode_instantiator_pointer, \ 26 encode_literal_constant, encode_literal_constant_member, \ 27 encode_literal_constant_size, encode_literal_constant_value, \ 28 encode_literal_data_initialiser, \ 29 encode_literal_instantiator, encode_literal_reference, \ 30 encode_path, encode_pcode, encode_pos, encode_ppos, \ 31 encode_predefined_reference, encode_size, \ 32 encode_symbol, encode_tablename, \ 33 encode_type_attribute, decode_type_attribute, \ 34 is_type_attribute 35 from os import listdir, mkdir, remove 36 from os.path import exists, isdir, join, split, splitext 37 from referencing import Reference 38 39 class Generator(CommonOutput): 40 41 "A code generator." 42 43 # NOTE: These must be synchronised with the library. 44 45 function_type = "__builtins__.core.function" 46 int_type = "__builtins__.int.int" 47 none_type = "__builtins__.none.NoneType" 48 string_type = "__builtins__.str.string" 49 type_type = "__builtins__.core.type" 50 unicode_type = "__builtins__.unicode.utf8string" 51 52 none_value = "__builtins__.none.None" 53 54 predefined_constant_members = ( 55 ("__builtins__.boolean", "False"), 56 ("__builtins__.boolean", "True"), 57 ("__builtins__.none", "None"), 58 ("__builtins__.notimplemented", "NotImplemented"), 59 ) 60 61 literal_mapping_types = ( 62 "__builtins__.dict.dict", 63 ) 64 65 literal_sequence_types = ( 66 "__builtins__.list.list", 67 "__builtins__.tuple.tuple", 68 ) 69 70 literal_instantiator_types = literal_mapping_types + literal_sequence_types 71 72 def __init__(self, importer, optimiser, output): 73 74 """ 75 Initialise the generator with the given 'importer', 'optimiser' and 76 'output' directory. 77 """ 78 79 self.importer = importer 80 self.optimiser = optimiser 81 self.output = output 82 83 # The special instance indicator. 84 85 self.instancepos = self.optimiser.attr_locations["__class__"] 86 87 def to_output(self, reset=False, debug=False, gc_sections=False): 88 89 "Write the generated code." 90 91 self.check_output("debug=%r gc_sections=%r" % (debug, gc_sections)) 92 self.write_structures() 93 self.write_scripts(debug, gc_sections) 94 self.copy_templates(reset) 95 96 def copy_templates(self, reset=False): 97 98 "Copy template files to the generated output directory." 99 100 templates = join(split(__file__)[0], "templates") 101 102 only_if_newer = not reset 103 104 for filename in listdir(templates): 105 target = self.output 106 pathname = join(templates, filename) 107 108 # Copy files into the target directory. 109 110 if not isdir(pathname): 111 copy(pathname, target, only_if_newer) 112 113 # Copy directories (such as the native code directory). 114 115 else: 116 target = join(self.output, filename) 117 118 if not exists(target): 119 mkdir(target) 120 121 existing = listdir(target) 122 needed = listdir(pathname) 123 124 # Determine which files are superfluous by comparing their 125 # basenames (without extensions) to those of the needed 126 # filenames. This should preserve object files for needed source 127 # files, only discarding completely superfluous files from the 128 # target directory. 129 130 needed_basenames = set() 131 for filename in needed: 132 needed_basenames.add(splitext(filename)[0]) 133 134 superfluous = [] 135 for filename in existing: 136 if splitext(filename)[0] not in needed_basenames: 137 superfluous.append(filename) 138 139 # Copy needed files. 140 141 for filename in needed: 142 copy(join(pathname, filename), target, only_if_newer) 143 144 # Remove superfluous files. 145 146 for filename in superfluous: 147 remove(join(target, filename)) 148 149 def write_structures(self): 150 151 "Write structures used by the program." 152 153 f_consts = open(join(self.output, "progconsts.h"), "w") 154 f_defs = open(join(self.output, "progtypes.c"), "w") 155 f_decls = open(join(self.output, "progtypes.h"), "w") 156 f_signatures = open(join(self.output, "main.h"), "w") 157 f_code = open(join(self.output, "main.c"), "w") 158 159 try: 160 # Output boilerplate. 161 162 print >>f_consts, """\ 163 #ifndef __PROGCONSTS_H__ 164 #define __PROGCONSTS_H__ 165 166 #include "types.h" 167 """ 168 print >>f_decls, """\ 169 #ifndef __PROGTYPES_H__ 170 #define __PROGTYPES_H__ 171 172 #include "progconsts.h" 173 #include "types.h" 174 """ 175 print >>f_defs, """\ 176 #include "progtypes.h" 177 #include "progops.h" 178 #include "main.h" 179 """ 180 print >>f_signatures, """\ 181 #ifndef __MAIN_H__ 182 #define __MAIN_H__ 183 184 #include "types.h" 185 """ 186 print >>f_code, """\ 187 #include <string.h> 188 #include <stdio.h> 189 #include "gc.h" 190 #include "types.h" 191 #include "exceptions.h" 192 #include "ops.h" 193 #include "progconsts.h" 194 #include "progtypes.h" 195 #include "main.h" 196 #include "progops.h" 197 """ 198 199 # Generate table and structure data. 200 201 function_instance_attrs = None 202 objects = self.optimiser.attr_table.items() 203 objects.sort() 204 205 self.callables = {} 206 207 for ref, indexes in objects: 208 attrnames = self.get_attribute_names(indexes) 209 210 kind = ref.get_kind() 211 path = ref.get_origin() 212 table_name = encode_tablename(kind, path) 213 structure_size = encode_size(kind, path) 214 215 # Generate structures for classes and modules. 216 217 if kind != "<instance>": 218 structure = [] 219 attrs = self.get_static_attributes(kind, path, attrnames) 220 221 # Set a special instantiator on the class. 222 223 if kind == "<class>": 224 225 # Write instantiator declarations based on the 226 # applicable initialiser. 227 228 init_ref = attrs["__init__"] 229 230 # Write instantiator definitions. 231 232 self.write_instantiator(f_code, f_signatures, path, init_ref) 233 234 # Record the callable for parameter table generation. 235 236 self.callables[path] = init_ref.get_origin() 237 238 # Define special attributes. 239 240 attrs["__fn__"] = path 241 attrs["__args__"] = path 242 243 self.populate_structure(Reference(kind, path), attrs, kind, structure) 244 245 if kind == "<class>": 246 self.write_instance_structure(f_decls, path, structure_size) 247 248 self.write_structure(f_decls, f_defs, path, table_name, structure, 249 kind == "<class>" and path) 250 251 # Record function instance details for function generation below. 252 253 else: 254 attrs = self.get_instance_attributes(path, attrnames) 255 if path == self.function_type: 256 function_instance_attrs = attrs 257 258 # Record the callable for parameter table generation. 259 260 self.callables[path] = path 261 262 # Write a table for all objects. 263 264 table = [] 265 self.populate_table(Reference(kind, path), table) 266 self.write_table(f_decls, f_defs, table_name, structure_size, table) 267 268 # Generate function instances. 269 270 functions = self.importer.function_parameters.keys() 271 functions.sort() 272 extra_function_instances = [] 273 274 for path in functions: 275 276 # Instantiators are generated above. 277 278 if self.importer.classes.has_key(path) or not self.importer.get_object(path): 279 continue 280 281 # Record the callable for parameter table generation. 282 283 self.callables[path] = path 284 285 # Define the structure details. 286 287 cls = self.function_type 288 table_name = encode_tablename("<instance>", cls) 289 structure_size = encode_size("<instance>", path) 290 291 # Set a special callable attribute on the instance. 292 293 function_instance_attrs["__fn__"] = path 294 function_instance_attrs["__args__"] = path 295 296 structure = self.populate_function(path, function_instance_attrs) 297 self.write_structure(f_decls, f_defs, path, table_name, structure) 298 299 # Functions with defaults need to declare instance structures. 300 301 if self.importer.function_defaults.get(path): 302 self.write_instance_structure(f_decls, path, structure_size) 303 extra_function_instances.append(path) 304 305 # Write function declarations. 306 # Signature: __attr <name>(__attr[]); 307 308 print >>f_signatures, "__attr %s(__attr args[]);" % encode_function_pointer(path) 309 310 # Generate parameter table size data. 311 312 min_parameters = {} 313 max_parameters = {} 314 size_parameters = {} 315 316 # Consolidate parameter tables for instantiators and functions. 317 318 parameter_tables = set() 319 320 for path, function_path in self.callables.items(): 321 argmin, argmax = self.get_argument_limits(function_path) 322 323 # Obtain the parameter table members. 324 325 parameters = self.optimiser.parameters[function_path] 326 if not parameters: 327 parameters = () 328 else: 329 parameters = tuple(parameters) 330 331 # Define each table in terms of the members and the minimum 332 # number of arguments. 333 334 parameter_tables.add((argmin, parameters)) 335 signature = self.get_parameter_signature(argmin, parameters) 336 337 # Record the minimum number of arguments, the maximum number, 338 # and the size of the table. 339 340 min_parameters[signature] = argmin 341 max_parameters[signature] = argmax 342 size_parameters[signature] = len(parameters) 343 344 self.write_size_constants(f_consts, "pmin", min_parameters, 0) 345 self.write_size_constants(f_consts, "pmax", max_parameters, 0) 346 self.write_size_constants(f_consts, "psize", size_parameters, 0) 347 348 # Generate parameter tables for distinct function signatures. 349 350 for argmin, parameters in parameter_tables: 351 self.make_parameter_table(f_decls, f_defs, argmin, parameters) 352 353 # Generate predefined constants. 354 355 for path, name in self.predefined_constant_members: 356 self.make_predefined_constant(f_decls, f_defs, path, name) 357 358 # Generate literal constants. 359 360 for constant, n in self.optimiser.constants.items(): 361 self.make_literal_constant(f_decls, f_defs, n, constant) 362 363 # Generate a common integer instance object, referenced when integer 364 # attributes are accessed. 365 366 self.make_common_integer(f_decls, f_defs) 367 368 # Finish the main source file. 369 370 self.write_main_program(f_code, f_signatures) 371 372 # Record size information for certain function instances as well as 373 # for classes, modules and other instances. 374 375 size_tables = {} 376 377 for kind in ["<class>", "<module>", "<instance>"]: 378 size_tables[kind] = {} 379 380 # Generate structure size data. 381 382 for ref, structure in self.optimiser.structures.items(): 383 size_tables[ref.get_kind()][ref.get_origin()] = len(structure) 384 385 for path in extra_function_instances: 386 defaults = self.importer.function_defaults[path] 387 size_tables["<instance>"][path] = size_tables["<instance>"][self.function_type] + len(defaults) 388 389 size_tables = size_tables.items() 390 size_tables.sort() 391 392 for kind, sizes in size_tables: 393 self.write_size_constants(f_consts, kind, sizes, 0) 394 395 # Generate parameter codes. 396 397 self.write_code_constants(f_consts, self.optimiser.all_paramnames, 398 self.optimiser.arg_locations, 399 "pcode", "ppos", encode_pcode, encode_ppos) 400 401 # Generate attribute codes. 402 403 self.write_code_constants(f_consts, self.optimiser.all_attrnames, 404 self.optimiser.locations, 405 "code", "pos", encode_code, encode_pos) 406 407 # Output more boilerplate. 408 409 print >>f_consts, """\ 410 411 #endif /* __PROGCONSTS_H__ */""" 412 413 print >>f_decls, """\ 414 415 #define __FUNCTION_TYPE %s 416 #define __FUNCTION_INSTANCE_SIZE %s 417 #define __TYPE_CLASS_TYPE %s 418 #define __TYPE_CLASS_POS %s 419 #define __TYPE_CLASS_CODE %s 420 421 #endif /* __PROGTYPES_H__ */""" % ( 422 encode_path(self.function_type), 423 encode_size("<instance>", self.function_type), 424 encode_path(self.type_type), 425 encode_pos(encode_type_attribute(self.type_type)), 426 encode_code(encode_type_attribute(self.type_type)), 427 ) 428 429 print >>f_signatures, """\ 430 431 #endif /* __MAIN_H__ */""" 432 433 finally: 434 f_consts.close() 435 f_defs.close() 436 f_decls.close() 437 f_signatures.close() 438 f_code.close() 439 440 def write_scripts(self, debug, gc_sections): 441 442 "Write scripts used to build the program." 443 444 # Options affect compiling and linking. 445 446 f_options = open(join(self.output, "options.mk"), "w") 447 try: 448 if debug: 449 print >>f_options, "CFLAGS = -g" 450 else: 451 print >>f_options, "CFLAGS = -O2" 452 453 if gc_sections: 454 print >>f_options, "include gc_sections.mk" 455 456 finally: 457 f_options.close() 458 459 # Native and module definitions divide the program modules into native 460 # and generated code. 461 462 f_native = open(join(self.output, "native.mk"), "w") 463 f_modules = open(join(self.output, "modules.mk"), "w") 464 try: 465 # Identify modules used by the program. 466 467 native_modules = [join("native", "common.c")] 468 modules = [] 469 470 for name in self.importer.modules.keys(): 471 parts = name.split(".", 1) 472 473 # Identify source files to be built. 474 475 if parts[0] == "native": 476 native_modules.append(join("native", "%s.c" % parts[1])) 477 else: 478 modules.append(join("src", "%s.c" % name)) 479 480 print >>f_native, "SRC =", " ".join(native_modules) 481 print >>f_modules, "SRC +=", " ".join(modules) 482 483 finally: 484 f_native.close() 485 f_modules.close() 486 487 # Instance position configuration uses the position of the ubiquitous 488 # __class__ attribute as a means of indicating that an object is an 489 # instance. Classes employ special identifying attributes that are 490 # positioned elsewhere and thus cannot be in the same location as the 491 # __class__ attribute. 492 493 f_instancepos = open(join(self.output, "instancepos.h"), "w") 494 try: 495 print >>f_instancepos, """\ 496 #ifndef __INSTANCEPOS 497 #define __INSTANCEPOS %d 498 #endif 499 """ % self.instancepos 500 finally: 501 f_instancepos.close() 502 503 def make_literal_constant(self, f_decls, f_defs, n, constant): 504 505 """ 506 Write literal constant details to 'f_decls' (to declare a structure) and 507 to 'f_defs' (to define the contents) for the constant with the number 508 'n' with the given 'constant'. 509 """ 510 511 value, value_type, encoding = constant 512 513 # Do not generate individual integer constants. 514 515 if value_type == self.int_type: 516 return 517 518 const_path = encode_literal_constant(n) 519 structure_name = encode_literal_reference(n) 520 521 ref = Reference("<instance>", value_type) 522 self.make_constant(f_decls, f_defs, ref, const_path, structure_name, value, encoding) 523 524 def make_predefined_constant(self, f_decls, f_defs, path, name): 525 526 """ 527 Write predefined constant details to 'f_decls' (to declare a structure) 528 and to 'f_defs' (to define the contents) for the constant located in 529 'path' with the given 'name'. 530 """ 531 532 # Determine the details of the constant. 533 534 attr_path = "%s.%s" % (path, name) 535 structure_name = encode_predefined_reference(attr_path) 536 ref = self.importer.get_object(attr_path) 537 538 self.make_constant(f_decls, f_defs, ref, attr_path, structure_name) 539 540 def make_common_integer(self, f_decls, f_defs): 541 542 """ 543 Write common integer instance details to 'f_decls' (to declare a 544 structure) and to 'f_defs' (to define the contents). 545 """ 546 547 ref = Reference("<instance>", self.int_type) 548 self.make_constant(f_decls, f_defs, ref, "__common_integer", "__common_integer_obj") 549 550 def make_constant(self, f_decls, f_defs, ref, const_path, structure_name, data=None, encoding=None): 551 552 """ 553 Write constant details to 'f_decls' (to declare a structure) and to 554 'f_defs' (to define the contents) for the constant described by 'ref' 555 having the given 'const_path' (providing an attribute for the constant) 556 and 'structure_name' (for the constant structure itself). 557 558 The additional 'data' and 'encoding' are used to describe specific 559 values. 560 """ 561 562 # Obtain the attributes. 563 564 cls = ref.get_origin() 565 indexes = self.optimiser.attr_table[ref] 566 attrnames = self.get_attribute_names(indexes) 567 attrs = self.get_instance_attributes(cls, attrnames) 568 569 # Set the data, if provided. 570 571 if data is not None: 572 attrs["__data__"] = data 573 574 # Also set a key for dynamic attribute lookup, if a string. 575 576 if attrs.has_key("__key__"): 577 if data in self.optimiser.all_attrnames: 578 attrs["__key__"] = data 579 else: 580 attrs["__key__"] = None 581 582 # Initialise the size, if a string. 583 584 if attrs.has_key("__size__"): 585 attrs["__size__"] = len(data) 586 587 # Define Unicode constant encoding details. 588 589 if cls == self.unicode_type: 590 591 # Reference the encoding's own constant value. 592 593 if encoding: 594 n = self.optimiser.constants[(encoding, self.string_type, None)] 595 596 # Employ a special alias that will be tested specifically in 597 # encode_member. 598 599 encoding_ref = Reference("<instance>", self.string_type, "$c%s" % n) 600 601 # Use None where no encoding was indicated. 602 603 else: 604 encoding_ref = Reference("<instance>", self.none_type) 605 606 attrs["encoding"] = encoding_ref 607 608 # Define the structure details. An object is created for the constant, 609 # but an attribute is provided, referring to the object, for access to 610 # the constant in the program. 611 612 structure = [] 613 table_name = encode_tablename("<instance>", cls) 614 self.populate_structure(ref, attrs, ref.get_kind(), structure) 615 self.write_structure(f_decls, f_defs, structure_name, table_name, structure) 616 617 # Define a macro for the constant. 618 619 attr_name = encode_path(const_path) 620 print >>f_decls, "#define %s __ATTRVALUE(&%s)" % (attr_name, structure_name) 621 622 def make_parameter_table(self, f_decls, f_defs, argmin, parameters): 623 624 """ 625 Write parameter table details to 'f_decls' (to declare a table) and to 626 'f_defs' (to define the contents) for the given 'argmin' and 627 'parameters'. 628 """ 629 630 # Use a signature for the table name instead of a separate name for each 631 # function. 632 633 signature = self.get_parameter_signature(argmin, parameters) 634 table_name = encode_tablename("<function>", signature) 635 min_parameters = encode_size("pmin", signature) 636 max_parameters = encode_size("pmax", signature) 637 structure_size = encode_size("psize", signature) 638 639 table = [] 640 self.populate_parameter_table(parameters, table) 641 self.write_parameter_table(f_decls, f_defs, table_name, min_parameters, max_parameters, structure_size, table) 642 643 def get_parameter_signature(self, argmin, parameters): 644 645 "Return a signature for the given 'argmin' and 'parameters'." 646 647 l = [str(argmin)] 648 for parameter in parameters: 649 if parameter is None: 650 l.append("") 651 else: 652 name, pos = parameter 653 l.append("%s_%s" % (name, pos)) 654 return l and "__".join(l) or "__void" 655 656 def get_signature_for_callable(self, path): 657 658 "Return the signature for the callable with the given 'path'." 659 660 function_path = self.callables[path] 661 argmin, argmax = self.get_argument_limits(function_path) 662 parameters = self.optimiser.parameters[function_path] 663 return self.get_parameter_signature(argmin, parameters) 664 665 def write_size_constants(self, f_consts, size_prefix, sizes, padding): 666 667 """ 668 Write size constants to 'f_consts' for the given 'size_prefix', using 669 the 'sizes' dictionary to populate the definition, adding the given 670 'padding' to the basic sizes. 671 """ 672 673 print >>f_consts, "enum %s {" % encode_size(size_prefix) 674 first = True 675 for path, size in sizes.items(): 676 if not first: 677 print >>f_consts, "," 678 else: 679 first = False 680 f_consts.write(" %s = %d" % (encode_size(size_prefix, path), size + padding)) 681 print >>f_consts, "\n };" 682 683 def write_code_constants(self, f_consts, attrnames, locations, code_prefix, 684 pos_prefix, code_encoder, pos_encoder): 685 686 """ 687 Write code constants to 'f_consts' for the given 'attrnames' and 688 attribute 'locations'. 689 """ 690 691 print >>f_consts, "enum %s {" % encode_symbol(code_prefix) 692 first = True 693 for i, attrname in enumerate(attrnames): 694 if not first: 695 print >>f_consts, "," 696 else: 697 first = False 698 f_consts.write(" %s = %d" % (code_encoder(attrname), i)) 699 print >>f_consts, "\n };" 700 701 print >>f_consts, "enum %s {" % encode_symbol(pos_prefix) 702 first = True 703 for i, attrnames in enumerate(locations): 704 for attrname in attrnames: 705 if not first: 706 print >>f_consts, "," 707 else: 708 first = False 709 f_consts.write(" %s = %d" % (pos_encoder(attrname), i)) 710 print >>f_consts, "\n };" 711 712 def write_table(self, f_decls, f_defs, table_name, structure_size, table): 713 714 """ 715 Write the declarations to 'f_decls' and definitions to 'f_defs' for 716 the object having the given 'table_name' and the given 'structure_size', 717 with 'table' details used to populate the definition. 718 """ 719 720 print >>f_decls, "extern const __table %s;\n" % table_name 721 722 # Write the corresponding definition. 723 724 print >>f_defs, """\ 725 const __table %s = { 726 %s, 727 { 728 %s 729 } 730 }; 731 """ % (table_name, structure_size, 732 ",\n ".join(table)) 733 734 def write_parameter_table(self, f_decls, f_defs, table_name, min_parameters, 735 max_parameters, structure_size, table): 736 737 """ 738 Write the declarations to 'f_decls' and definitions to 'f_defs' for 739 the object having the given 'table_name' and the given 'min_parameters', 740 'max_parameters' and 'structure_size', with 'table' details used to 741 populate the definition. 742 """ 743 744 members = [] 745 for t in table: 746 members.append("{.code=%s, .pos=%s}" % t) 747 748 print >>f_decls, "extern const __ptable %s;\n" % table_name 749 750 # Write the corresponding definition. 751 752 print >>f_defs, """\ 753 const __ptable %s = { 754 .min=%s, 755 .max=%s, 756 .size=%s, 757 { 758 %s 759 } 760 }; 761 """ % (table_name, min_parameters, max_parameters, structure_size, 762 ",\n ".join(members)) 763 764 def write_instance_structure(self, f_decls, path, structure_size): 765 766 """ 767 Write a declaration to 'f_decls' for the object having the given 'path' 768 and the given 'structure_size'. 769 """ 770 771 # Write an instance-specific type definition for instances of classes. 772 # See: templates/types.h 773 774 print >>f_decls, """\ 775 typedef struct { 776 const __table * table; 777 __pos pos; 778 __attr attrs[%s]; 779 } %s; 780 """ % (structure_size, encode_symbol("obj", path)) 781 782 def write_structure(self, f_decls, f_defs, structure_name, table_name, structure, path=None): 783 784 """ 785 Write the declarations to 'f_decls' and definitions to 'f_defs' for 786 the object having the given 'structure_name', the given 'table_name', 787 and the given 'structure' details used to populate the definition. 788 """ 789 790 if f_decls: 791 print >>f_decls, "extern __obj %s;\n" % encode_path(structure_name) 792 793 is_class = path and self.importer.get_object(path).has_kind("<class>") 794 pos = is_class and encode_pos(encode_type_attribute(path)) or str(self.instancepos) 795 796 print >>f_defs, """\ 797 __obj %s = { 798 &%s, 799 %s, 800 { 801 %s 802 }}; 803 """ % ( 804 encode_path(structure_name), table_name, pos, 805 ",\n ".join(structure)) 806 807 def get_argument_limits(self, path): 808 809 """ 810 Return the argument minimum and maximum for the callable at 'path', 811 adding an argument position for a universal context. 812 """ 813 814 parameters = self.importer.function_parameters[path] 815 defaults = self.importer.function_defaults.get(path) 816 num_parameters = len(parameters) + 1 817 return num_parameters - (defaults and len(defaults) or 0), num_parameters 818 819 def get_attribute_names(self, indexes): 820 821 """ 822 Given a list of attribute table 'indexes', return a list of attribute 823 names. 824 """ 825 826 all_attrnames = self.optimiser.all_attrnames 827 attrnames = [] 828 for i in indexes: 829 if i is None: 830 attrnames.append(None) 831 else: 832 attrnames.append(all_attrnames[i]) 833 return attrnames 834 835 def get_static_attributes(self, kind, name, attrnames): 836 837 """ 838 Return a mapping of attribute names to paths for attributes belonging 839 to objects of the given 'kind' (being "<class>" or "<module>") with 840 the given 'name' and supporting the given 'attrnames'. 841 """ 842 843 attrs = {} 844 845 for attrname in attrnames: 846 if attrname is None: 847 continue 848 if kind == "<class>": 849 path = self.importer.all_class_attrs[name][attrname] 850 elif kind == "<module>": 851 path = "%s.%s" % (name, attrname) 852 else: 853 continue 854 855 # The module may be hidden. 856 857 attr = self.importer.get_object(path) 858 if not attr: 859 module = self.importer.hidden.get(path) 860 if module: 861 attr = Reference(module.name, "<module>") 862 attrs[attrname] = attr 863 864 return attrs 865 866 def get_instance_attributes(self, name, attrnames): 867 868 """ 869 Return a mapping of attribute names to references for attributes 870 belonging to instances of the class with the given 'name', where the 871 given 'attrnames' are supported. 872 """ 873 874 consts = self.importer.all_instance_attr_constants[name] 875 attrs = {} 876 for attrname in attrnames: 877 if attrname is None: 878 continue 879 const = consts.get(attrname) 880 attrs[attrname] = const or Reference("<var>", "%s.%s" % (name, attrname)) 881 return attrs 882 883 def populate_table(self, path, table): 884 885 """ 886 Traverse the attributes in the determined order for the structure having 887 the given 'path', adding entries to the attribute 'table'. 888 """ 889 890 for attrname in self.optimiser.structures[path]: 891 892 # Handle gaps in the structure. 893 894 if attrname is None: 895 table.append("0") 896 else: 897 table.append(encode_code(attrname)) 898 899 def populate_parameter_table(self, parameters, table): 900 901 """ 902 Traverse the 'parameters' in the determined order, adding entries to the 903 attribute 'table'. 904 """ 905 906 for value in parameters: 907 908 # Handle gaps in the structure. 909 910 if value is None: 911 table.append(("0", "0")) 912 else: 913 name, pos = value 914 table.append((encode_symbol("pcode", name), pos)) 915 916 def populate_function(self, path, function_instance_attrs): 917 918 """ 919 Populate a structure for the function with the given 'path'. The given 920 'attrs' provide the instance attributes. 921 """ 922 923 structure = [] 924 self.populate_structure(Reference("<function>", path), function_instance_attrs, "<instance>", structure) 925 926 # Append default members. 927 928 self.append_defaults(path, structure) 929 return structure 930 931 def populate_structure(self, ref, attrs, kind, structure): 932 933 """ 934 Traverse the attributes in the determined order for the structure having 935 the given 'ref' whose members are provided by the 'attrs' mapping, in a 936 structure of the given 'kind', adding entries to the object 'structure'. 937 """ 938 939 # Populate function instance structures for functions. 940 941 if ref.has_kind("<function>"): 942 origin = self.function_type 943 structure_ref = Reference("<instance>", self.function_type) 944 945 # Otherwise, just populate the appropriate structures. 946 947 else: 948 origin = ref.get_origin() 949 structure_ref = ref 950 951 for attrname in self.optimiser.structures[structure_ref]: 952 953 # Handle gaps in the structure. 954 955 if attrname is None: 956 structure.append("__NULL") 957 958 # Handle non-constant and constant members. 959 960 else: 961 attr = attrs[attrname] 962 963 # Special function pointer member. 964 965 if attrname == "__fn__": 966 967 # Classes offer instantiators which can be called without a 968 # context. 969 970 if kind == "<class>": 971 attr = encode_instantiator_pointer(attr) 972 else: 973 attr = encode_function_pointer(attr) 974 975 structure.append("{.fn=%s}" % attr) 976 continue 977 978 # Special argument specification member. 979 980 elif attrname == "__args__": 981 signature = self.get_signature_for_callable(ref.get_origin()) 982 ptable = encode_tablename("<function>", signature) 983 984 structure.append("{.ptable=&%s}" % ptable) 985 continue 986 987 # Special internal data member. 988 989 elif attrname == "__data__": 990 structure.append("{.%s=%s}" % ( 991 encode_literal_constant_member(attr), 992 encode_literal_constant_value(attr))) 993 continue 994 995 # Special internal size member. 996 997 elif attrname == "__size__": 998 structure.append("__INTVALUE(%d)" % attr) 999 continue 1000 1001 # Special internal key member. 1002 1003 elif attrname == "__key__": 1004 structure.append("{.code=%s, .pos=%s}" % (attr and encode_code(attr) or "0", 1005 attr and encode_pos(attr) or "0")) 1006 continue 1007 1008 # Special cases. 1009 1010 elif attrname in ("__file__", "__name__"): 1011 path = ref.get_origin() 1012 value_type = self.string_type 1013 1014 # Provide constant values. These must match the values 1015 # originally recorded during inspection. 1016 1017 if attrname == "__file__": 1018 module = self.importer.get_module(path) 1019 value = module.filename 1020 1021 # Function and class names are leafnames. 1022 1023 elif attrname == "__name__" and not ref.has_kind("<module>"): 1024 value = path.rsplit(".", 1)[-1] 1025 1026 # All other names just use the object path information. 1027 1028 else: 1029 value = path 1030 1031 encoding = None 1032 1033 local_number = self.importer.all_constants[path][(value, value_type, encoding)] 1034 constant_name = "$c%d" % local_number 1035 attr_path = "%s.%s" % (path, constant_name) 1036 constant_number = self.optimiser.constant_numbers[attr_path] 1037 constant_value = "__const%s" % constant_number 1038 structure.append("%s /* %s */" % (constant_value, attrname)) 1039 continue 1040 1041 elif attrname == "__parent__": 1042 path = ref.get_origin() 1043 1044 # Parents of classes and functions are derived from their 1045 # object paths. 1046 1047 value = path.rsplit(".", 1)[0] 1048 structure.append("{.value=&%s}" % encode_path(value)) 1049 continue 1050 1051 # Special context member. 1052 # Set the context depending on the kind of attribute. 1053 # For methods: <parent> 1054 # For other attributes: __NULL 1055 1056 elif attrname == "__context__": 1057 path = ref.get_origin() 1058 1059 # Contexts of methods are derived from their object paths. 1060 1061 context = "0" 1062 1063 if ref.get_kind() == "<function>": 1064 parent = path.rsplit(".", 1)[0] 1065 if self.importer.classes.has_key(parent): 1066 context = "&%s" % encode_path(parent) 1067 1068 structure.append("{.value=%s}" % context) 1069 continue 1070 1071 # Special class relationship attributes. 1072 1073 elif is_type_attribute(attrname): 1074 structure.append("{.value=&%s}" % encode_path(decode_type_attribute(attrname))) 1075 continue 1076 1077 # All other kinds of members. 1078 1079 structure.append(self.encode_member(origin, attrname, attr, kind)) 1080 1081 def encode_member(self, path, name, ref, structure_type): 1082 1083 """ 1084 Encode within the structure provided by 'path', the member whose 'name' 1085 provides 'ref', within the given 'structure_type'. 1086 """ 1087 1088 kind = ref.get_kind() 1089 origin = ref.get_origin() 1090 1091 # References to constant literals. 1092 1093 if kind == "<instance>" and ref.is_constant_alias(): 1094 alias = ref.get_name() 1095 1096 # Use the alias directly if appropriate. 1097 1098 if alias.startswith("$c"): 1099 constant_value = encode_literal_constant(alias[2:]) 1100 return "%s /* %s */" % (constant_value, name) 1101 1102 # Obtain a constant value directly assigned to the attribute. 1103 1104 if self.optimiser.constant_numbers.has_key(alias): 1105 1106 # Encode integer constants differently. 1107 1108 value, value_type, encoding = self.importer.all_constant_values[alias] 1109 if value_type == self.int_type: 1110 return "__INTVALUE(%s) /* %s */" % (value, name) 1111 1112 constant_number = self.optimiser.constant_numbers[alias] 1113 constant_value = encode_literal_constant(constant_number) 1114 return "%s /* %s */" % (constant_value, name) 1115 1116 # Usage of predefined constants, currently only None supported. 1117 1118 if kind == "<instance>" and origin == self.none_type: 1119 attr_path = encode_predefined_reference(self.none_value) 1120 return "{.value=&%s} /* %s */" % (attr_path, name) 1121 1122 # Predefined constant members. 1123 1124 if (path, name) in self.predefined_constant_members: 1125 attr_path = encode_predefined_reference("%s.%s" % (path, name)) 1126 return "{.value=&%s} /* %s */" % (attr_path, name) 1127 1128 # General undetermined members. 1129 1130 if kind in ("<var>", "<instance>"): 1131 attr_path = encode_predefined_reference(self.none_value) 1132 return "{.value=&%s} /* %s */" % (attr_path, name) 1133 1134 else: 1135 return "{.value=&%s}" % encode_path(origin) 1136 1137 def append_defaults(self, path, structure): 1138 1139 """ 1140 For the given 'path', append default parameter members to the given 1141 'structure'. 1142 """ 1143 1144 for name, default in self.importer.function_defaults.get(path): 1145 structure.append(self.encode_member(path, name, default, "<instance>")) 1146 1147 def write_instantiator(self, f_code, f_signatures, path, init_ref): 1148 1149 """ 1150 Write an instantiator to 'f_code', with a signature to 'f_signatures', 1151 for instances of the class with the given 'path', with 'init_ref' as the 1152 initialiser function reference. 1153 1154 NOTE: This also needs to initialise any __fn__ and __args__ members 1155 NOTE: where __call__ is provided by the class. 1156 """ 1157 1158 parameters = self.importer.function_parameters[init_ref.get_origin()] 1159 1160 print >>f_code, """\ 1161 __attr %s(__attr __args[]) 1162 { 1163 /* Allocate the structure. */ 1164 __args[0] = __NEWINSTANCE(%s); 1165 1166 /* Call the initialiser. */ 1167 %s(__args); 1168 1169 /* Return the allocated object details. */ 1170 return __args[0]; 1171 } 1172 """ % ( 1173 encode_instantiator_pointer(path), 1174 encode_path(path), 1175 encode_function_pointer(init_ref.get_origin()) 1176 ) 1177 1178 print >>f_signatures, "#define __HAVE_%s" % encode_path(path) 1179 print >>f_signatures, "__attr %s(__attr[]);" % encode_instantiator_pointer(path) 1180 1181 # Write additional literal instantiators. These do not call the 1182 # initialisers but instead populate the structures directly. 1183 1184 if path in self.literal_instantiator_types: 1185 if path in self.literal_mapping_types: 1186 style = "mapping" 1187 else: 1188 style = "sequence" 1189 1190 print >>f_code, """\ 1191 __attr %s(__attr __args[], __pos number) 1192 { 1193 /* Allocate the structure. */ 1194 __args[0] = __NEWINSTANCE(%s); 1195 1196 /* Allocate a structure for the data and set it on the __data__ attribute. */ 1197 %s(__args, number); 1198 1199 /* Return the allocated object details. */ 1200 return __args[0]; 1201 } 1202 """ % ( 1203 encode_literal_instantiator(path), 1204 encode_path(path), 1205 encode_literal_data_initialiser(style) 1206 ) 1207 1208 print >>f_signatures, "__attr %s(__attr[], __pos);" % encode_literal_instantiator(path) 1209 1210 def write_main_program(self, f_code, f_signatures): 1211 1212 """ 1213 Write the main program to 'f_code', invoking the program's modules. Also 1214 write declarations for module main functions to 'f_signatures'. 1215 """ 1216 1217 print >>f_code, """\ 1218 int main(int argc, char *argv[]) 1219 { 1220 __exc __tmp_exc; 1221 1222 GC_INIT(); 1223 1224 __Try 1225 {""" 1226 1227 for name in self.importer.order_modules(): 1228 function_name = "__main_%s" % encode_path(name) 1229 print >>f_signatures, "void %s();" % function_name 1230 1231 # Omit the native modules. 1232 1233 parts = name.split(".") 1234 1235 if parts[0] != "native": 1236 print >>f_code, """\ 1237 %s();""" % function_name 1238 1239 print >>f_code, """\ 1240 } 1241 __Catch(__tmp_exc) 1242 { 1243 if (__ISINSTANCE(__tmp_exc.arg, __ATTRVALUE(&__builtins___exception_system_SystemExit))) 1244 return __TOINT(__load_via_object(__VALUE(__tmp_exc.arg), value)); 1245 1246 fprintf(stderr, "Program terminated due to exception: %%s.\\n", 1247 __load_via_object( 1248 __VALUE(%s(__ARGS(__NULL, __tmp_exc.arg))), 1249 __data__).strvalue); 1250 return 1; 1251 } 1252 1253 return 0; 1254 } 1255 """ % encode_function_pointer("__builtins__.str.str") 1256 1257 # vim: tabstop=4 expandtab shiftwidth=4