Lichen

generator.py

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