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