Lichen

generator.py

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