1.1 --- a/generator.py Fri Dec 09 17:27:30 2016 +0100
1.2 +++ b/generator.py Fri Dec 09 19:42:33 2016 +0100
1.3 @@ -77,6 +77,12 @@
1.4 literal_instantiator_types = literal_mapping_types + literal_sequence_types
1.5
1.6 def __init__(self, importer, optimiser, output):
1.7 +
1.8 + """
1.9 + Initialise the generator with the given 'importer', 'optimiser' and
1.10 + 'output' directory.
1.11 + """
1.12 +
1.13 self.importer = importer
1.14 self.optimiser = optimiser
1.15 self.output = output
1.16 @@ -182,6 +188,8 @@
1.17 objects = self.optimiser.attr_table.items()
1.18 objects.sort()
1.19
1.20 + self.callables = {}
1.21 +
1.22 for ref, indexes in objects:
1.23 attrnames = self.get_attribute_names(indexes)
1.24
1.25 @@ -199,8 +207,6 @@
1.26 # Set a special instantiator on the class.
1.27
1.28 if kind == "<class>":
1.29 - attrs["__fn__"] = path
1.30 - attrs["__args__"] = encode_size("pmin", path)
1.31
1.32 # Write instantiator declarations based on the
1.33 # applicable initialiser.
1.34 @@ -211,9 +217,15 @@
1.35
1.36 self.write_instantiator(f_code, f_signatures, path, init_ref)
1.37
1.38 - # Write parameter table.
1.39 + # Record the callable for parameter table generation.
1.40 +
1.41 + self.callables[path] = init_ref.get_origin()
1.42
1.43 - self.make_parameter_table(f_decls, f_defs, path, init_ref.get_origin())
1.44 + # Define special attributes.
1.45 +
1.46 + signature = self.get_signature_for_callable(path)
1.47 + attrs["__fn__"] = path
1.48 + attrs["__args__"] = encode_size("pmin", signature)
1.49
1.50 self.populate_structure(Reference(kind, path), attrs, kind, structure)
1.51
1.52 @@ -230,6 +242,10 @@
1.53 if path == self.function_type:
1.54 function_instance_attrs = attrs
1.55
1.56 + # Record the callable for parameter table generation.
1.57 +
1.58 + self.callables[path] = path
1.59 +
1.60 # Write a table for all objects.
1.61
1.62 table = []
1.63 @@ -249,14 +265,21 @@
1.64 if self.importer.classes.has_key(path) or not self.importer.get_object(path):
1.65 continue
1.66
1.67 + # Record the callable for parameter table generation.
1.68 +
1.69 + self.callables[path] = path
1.70 +
1.71 + # Define the structure details.
1.72 +
1.73 cls = self.function_type
1.74 table_name = encode_tablename("<instance>", cls)
1.75 structure_size = encode_size("<instance>", path)
1.76
1.77 # Set a special callable attribute on the instance.
1.78
1.79 + signature = self.get_signature_for_callable(path)
1.80 function_instance_attrs["__fn__"] = path
1.81 - function_instance_attrs["__args__"] = encode_size("pmin", path)
1.82 + function_instance_attrs["__args__"] = encode_size("pmin", signature)
1.83
1.84 # Produce two structures where a method is involved.
1.85
1.86 @@ -295,9 +318,22 @@
1.87
1.88 print >>f_signatures, "__attr %s(__attr args[]);" % encode_function_pointer(path)
1.89
1.90 - # Write parameter table.
1.91 + # Consolidate parameter tables for instantiators and functions.
1.92 +
1.93 + parameter_tables = set()
1.94
1.95 - self.make_parameter_table(f_decls, f_defs, path, path)
1.96 + for path, function_path in self.callables.items():
1.97 + parameters = self.optimiser.parameters[function_path]
1.98 + if not parameters:
1.99 + parameters = ()
1.100 + else:
1.101 + parameters = tuple(parameters)
1.102 + parameter_tables.add(parameters)
1.103 +
1.104 + # Generate parameter tables for distinct function signatures.
1.105 +
1.106 + for parameters in parameter_tables:
1.107 + self.make_parameter_table(f_decls, f_defs, parameters)
1.108
1.109 # Generate predefined constants.
1.110
1.111 @@ -343,8 +379,12 @@
1.112
1.113 for path, parameters in self.optimiser.parameters.items():
1.114 argmin, argmax = self.get_argument_limits(path)
1.115 - min_sizes[path] = argmin
1.116 - max_sizes[path] = argmax
1.117 +
1.118 + # Use the parameter signature in the constant names.
1.119 +
1.120 + signature = self.get_parameter_signature(parameters)
1.121 + min_sizes[signature] = argmin
1.122 + max_sizes[signature] = argmax
1.123
1.124 # Record instantiator limits.
1.125
1.126 @@ -465,22 +505,45 @@
1.127 attr_name = encode_path(const_path)
1.128 print >>f_decls, "#define %s ((__attr) {&%s, &%s})" % (attr_name, structure_name, structure_name)
1.129
1.130 - def make_parameter_table(self, f_decls, f_defs, path, function_path):
1.131 + def make_parameter_table(self, f_decls, f_defs, parameters):
1.132
1.133 """
1.134 Write parameter table details to 'f_decls' (to declare a table) and to
1.135 - 'f_defs' (to define the contents) for the function with the given
1.136 - 'path', using 'function_path' to obtain the parameter details. The
1.137 - latter two arguments may differ when describing an instantiator using
1.138 - the details of an initialiser.
1.139 + 'f_defs' (to define the contents) for the given 'parameters'.
1.140 """
1.141
1.142 + # Use a signature for the table name instead of a separate name for each
1.143 + # function.
1.144 +
1.145 + signature = self.get_parameter_signature(parameters)
1.146 + table_name = encode_tablename("<function>", signature)
1.147 + structure_size = encode_size("pmax", signature)
1.148 +
1.149 table = []
1.150 - table_name = encode_tablename("<function>", path)
1.151 - structure_size = encode_size("pmax", path)
1.152 - self.populate_parameter_table(function_path, table)
1.153 + self.populate_parameter_table(parameters, table)
1.154 self.write_parameter_table(f_decls, f_defs, table_name, structure_size, table)
1.155
1.156 + def get_parameter_signature(self, parameters):
1.157 +
1.158 + "Return a signature for the given 'parameters'."
1.159 +
1.160 + l = []
1.161 + for parameter in parameters:
1.162 + if parameter is None:
1.163 + l.append("")
1.164 + else:
1.165 + name, pos = parameter
1.166 + l.append(name)
1.167 + return l and "__".join(l) or "__void"
1.168 +
1.169 + def get_signature_for_callable(self, path):
1.170 +
1.171 + "Return the signature for the callable with the given 'path'."
1.172 +
1.173 + function_path = self.callables[path]
1.174 + parameters = self.optimiser.parameters[function_path]
1.175 + return self.get_parameter_signature(parameters)
1.176 +
1.177 def write_size_constants(self, f_consts, size_prefix, sizes, padding):
1.178
1.179 """
1.180 @@ -678,14 +741,14 @@
1.181 attrs[attrname] = const or Reference("<var>", "%s.%s" % (name, attrname))
1.182 return attrs
1.183
1.184 - def populate_table(self, key, table):
1.185 + def populate_table(self, path, table):
1.186
1.187 """
1.188 Traverse the attributes in the determined order for the structure having
1.189 - the given 'key', adding entries to the attribute 'table'.
1.190 + the given 'path', adding entries to the attribute 'table'.
1.191 """
1.192
1.193 - for attrname in self.optimiser.structures[key]:
1.194 + for attrname in self.optimiser.structures[path]:
1.195
1.196 # Handle gaps in the structure.
1.197
1.198 @@ -694,14 +757,14 @@
1.199 else:
1.200 table.append(encode_symbol("code", attrname))
1.201
1.202 - def populate_parameter_table(self, key, table):
1.203 + def populate_parameter_table(self, parameters, table):
1.204
1.205 """
1.206 - Traverse the parameters in the determined order for the structure having
1.207 - the given 'key', adding entries to the attribute 'table'.
1.208 + Traverse the 'parameters' in the determined order, adding entries to the
1.209 + attribute 'table'.
1.210 """
1.211
1.212 - for value in self.optimiser.parameters[key]:
1.213 + for value in parameters:
1.214
1.215 # Handle gaps in the structure.
1.216
1.217 @@ -751,11 +814,6 @@
1.218 origin = ref.get_origin()
1.219 structure_ref = ref
1.220
1.221 - # Refer to instantiator function tables for classes, specific function
1.222 - # tables for individual functions.
1.223 -
1.224 - ptable = encode_tablename("<function>", ref.get_origin())
1.225 -
1.226 for attrname in self.optimiser.structures[structure_ref]:
1.227
1.228 # Handle gaps in the structure.
1.229 @@ -800,6 +858,9 @@
1.230 # Special argument specification member.
1.231
1.232 elif attrname == "__args__":
1.233 + signature = self.get_signature_for_callable(ref.get_origin())
1.234 + ptable = encode_tablename("<function>", signature)
1.235 +
1.236 structure.append("{.min=%s, .ptable=&%s}" % (attr, ptable))
1.237 continue
1.238