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