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