1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/generator.py Mon Oct 24 21:18:10 2016 +0200
1.3 @@ -0,0 +1,694 @@
1.4 +#!/usr/bin/env python
1.5 +
1.6 +"""
1.7 +Generate C code from object layouts and other deduced information.
1.8 +
1.9 +Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>
1.10 +
1.11 +This program is free software; you can redistribute it and/or modify it under
1.12 +the terms of the GNU General Public License as published by the Free Software
1.13 +Foundation; either version 3 of the License, or (at your option) any later
1.14 +version.
1.15 +
1.16 +This program is distributed in the hope that it will be useful, but WITHOUT
1.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.19 +details.
1.20 +
1.21 +You should have received a copy of the GNU General Public License along with
1.22 +this program. If not, see <http://www.gnu.org/licenses/>.
1.23 +"""
1.24 +
1.25 +from common import CommonOutput
1.26 +from encoders import encode_bound_reference, encode_function_pointer, \
1.27 + encode_instantiator_pointer, encode_path, encode_symbol
1.28 +from os import listdir
1.29 +from os.path import isdir, join, split
1.30 +from referencing import Reference
1.31 +
1.32 +def copy(source, target):
1.33 +
1.34 + "Copy a text file from 'source' to 'target'."
1.35 +
1.36 + if isdir(target):
1.37 + target = join(target, split(source)[-1])
1.38 + infile = open(source)
1.39 + outfile = open(target, "w")
1.40 + try:
1.41 + outfile.write(infile.read())
1.42 + finally:
1.43 + outfile.close()
1.44 + infile.close()
1.45 +
1.46 +class Generator(CommonOutput):
1.47 +
1.48 + "A code generator."
1.49 +
1.50 + function_type = "__builtins__.core.function"
1.51 +
1.52 + table_name_prefixes = {
1.53 + "<class>" : "Class",
1.54 + "<module>" : "Module",
1.55 + "<instance>" : "Instance"
1.56 + }
1.57 +
1.58 + structure_size_prefixes = {
1.59 + "<class>" : "c",
1.60 + "<module>" : "m",
1.61 + "<instance>" : "i"
1.62 + }
1.63 +
1.64 + def __init__(self, importer, optimiser, output):
1.65 + self.importer = importer
1.66 + self.optimiser = optimiser
1.67 + self.output = output
1.68 +
1.69 + def to_output(self):
1.70 +
1.71 + "Write the generated code."
1.72 +
1.73 + self.check_output()
1.74 + self.write_structures()
1.75 + self.copy_templates()
1.76 +
1.77 + def copy_templates(self):
1.78 +
1.79 + "Copy template files to the generated output directory."
1.80 +
1.81 + templates = join(split(__file__)[0], "templates")
1.82 +
1.83 + for filename in listdir(templates):
1.84 + copy(join(templates, filename), self.output)
1.85 +
1.86 + def write_structures(self):
1.87 +
1.88 + "Write structures used by the program."
1.89 +
1.90 + f_consts = open(join(self.output, "progconsts.h"), "w")
1.91 + f_defs = open(join(self.output, "progtypes.c"), "w")
1.92 + f_decls = open(join(self.output, "progtypes.h"), "w")
1.93 + f_signatures = open(join(self.output, "main.h"), "w")
1.94 + f_code = open(join(self.output, "main.c"), "w")
1.95 +
1.96 + try:
1.97 + # Output boilerplate.
1.98 +
1.99 + print >>f_consts, """\
1.100 +#ifndef __PROGCONSTS_H__
1.101 +#define __PROGCONSTS_H__
1.102 +"""
1.103 + print >>f_decls, """\
1.104 +#ifndef __PROGTYPES_H__
1.105 +#define __PROGTYPES_H__
1.106 +
1.107 +#include "progconsts.h"
1.108 +#include "types.h"
1.109 +"""
1.110 + print >>f_defs, """\
1.111 +#include "progtypes.h"
1.112 +#include "main.h"
1.113 +"""
1.114 + print >>f_signatures, """\
1.115 +#ifndef __MAIN_H__
1.116 +#define __MAIN_H__
1.117 +
1.118 +#include "types.h"
1.119 +"""
1.120 + print >>f_code, """\
1.121 +#include <string.h>
1.122 +#include "types.h"
1.123 +#include "ops.h"
1.124 +#include "progconsts.h"
1.125 +#include "progtypes.h"
1.126 +#include "progops.h"
1.127 +#include "main.h"
1.128 +"""
1.129 +
1.130 + # Generate structure size data.
1.131 +
1.132 + size_tables = {}
1.133 +
1.134 + for kind in ["<class>", "<module>", "<instance>"]:
1.135 + size_tables[kind] = {}
1.136 +
1.137 + for ref, structure in self.optimiser.structures.items():
1.138 + size_tables[ref.get_kind()][ref.get_origin()] = len(structure)
1.139 +
1.140 + size_tables = size_tables.items()
1.141 + size_tables.sort()
1.142 +
1.143 + for kind, sizes in size_tables:
1.144 + self.write_size_constants(f_consts, self.structure_size_prefixes[kind], sizes, 0)
1.145 +
1.146 + # Generate parameter table size data.
1.147 +
1.148 + min_sizes = {}
1.149 + max_sizes = {}
1.150 +
1.151 + for path, parameters in self.optimiser.parameters.items():
1.152 + argmin, argmax = self.get_argument_limits(path)
1.153 + min_sizes[path] = argmin
1.154 + max_sizes[path] = argmax
1.155 +
1.156 + # Record instantiator limits.
1.157 +
1.158 + if path.endswith(".__init__"):
1.159 + path = path[:-len(".__init__")]
1.160 + min_sizes[path] = argmin - 1
1.161 + max_sizes[path] = argmax - 1
1.162 +
1.163 + self.write_size_constants(f_consts, "pmin", min_sizes, 0)
1.164 + self.write_size_constants(f_consts, "pmax", max_sizes, 0)
1.165 +
1.166 + # Generate attribute codes.
1.167 +
1.168 + self.write_code_constants(f_consts, self.optimiser.all_attrnames, self.optimiser.locations)
1.169 +
1.170 + # Generate table and structure data.
1.171 +
1.172 + function_instance_attrs = None
1.173 + objects = self.optimiser.attr_table.items()
1.174 + objects.sort()
1.175 +
1.176 + for ref, indexes in objects:
1.177 + attrnames = self.get_attribute_names(indexes)
1.178 +
1.179 + kind = ref.get_kind()
1.180 + path = ref.get_origin()
1.181 + table_name = encode_tablename(self.table_name_prefixes[kind], path)
1.182 + structure_size = encode_size(self.structure_size_prefixes[kind], path)
1.183 +
1.184 + # Generate structures for classes and modules.
1.185 +
1.186 + if kind != "<instance>":
1.187 + structure = []
1.188 + attrs = self.get_static_attributes(kind, path, attrnames)
1.189 +
1.190 + # Set a special instantiator on the class.
1.191 +
1.192 + if kind == "<class>":
1.193 + attrs["__fn__"] = path
1.194 + attrs["__args__"] = encode_size("pmin", path)
1.195 +
1.196 + # Write instantiator declarations based on the
1.197 + # applicable initialiser.
1.198 +
1.199 + init_ref = attrs["__init__"]
1.200 +
1.201 + # Signature: __attr __new_<name>(__attr[]);
1.202 +
1.203 + print >>f_signatures, "__attr %s(__attr[]);" % encode_instantiator_pointer(path)
1.204 +
1.205 + # Write instantiator definitions.
1.206 +
1.207 + self.write_instantiator(f_code, path, init_ref)
1.208 +
1.209 + # Write parameter table.
1.210 +
1.211 + self.make_parameter_table(f_decls, f_defs, path, init_ref.get_origin())
1.212 +
1.213 + self.populate_structure(Reference(kind, path), attrs, kind, structure)
1.214 + self.write_structure(f_decls, f_defs, path, table_name, structure_size, structure)
1.215 +
1.216 + # Record function instance details for function generation below.
1.217 +
1.218 + else:
1.219 + attrs = self.get_instance_attributes(path, attrnames)
1.220 + if path == self.function_type:
1.221 + function_instance_attrs = attrs
1.222 +
1.223 + # Write a table for all objects.
1.224 +
1.225 + table = []
1.226 + self.populate_table(Reference(kind, path), table)
1.227 + self.write_table(f_decls, f_defs, table_name, structure_size, table)
1.228 +
1.229 + # Generate function instances.
1.230 +
1.231 + functions = set()
1.232 +
1.233 + for ref in self.importer.objects.values():
1.234 + if ref.has_kind("<function>"):
1.235 + functions.add(ref.get_origin())
1.236 +
1.237 + functions = list(functions)
1.238 + functions.sort()
1.239 +
1.240 + for path in functions:
1.241 + cls = self.function_type
1.242 + table_name = encode_tablename("Instance", cls)
1.243 + structure_size = encode_size(self.structure_size_prefixes["<instance>"], cls)
1.244 +
1.245 + # Set a special callable attribute on the instance.
1.246 +
1.247 + function_instance_attrs["__fn__"] = path
1.248 + function_instance_attrs["__args__"] = encode_size("pmin", path)
1.249 +
1.250 + # Produce two structures where a method is involved.
1.251 +
1.252 + ref = self.importer.get_object(path)
1.253 + parent_ref = self.importer.get_object(ref.parent())
1.254 + parent_kind = parent_ref and parent_ref.get_kind()
1.255 +
1.256 + # Populate and write each structure.
1.257 +
1.258 + if parent_kind == "<class>":
1.259 +
1.260 + # An unbound version of a method.
1.261 +
1.262 + structure = self.populate_function(path, function_instance_attrs, True)
1.263 + self.write_structure(f_decls, f_defs, path, table_name, structure_size, structure)
1.264 +
1.265 + # A bound version of a method.
1.266 +
1.267 + structure = self.populate_function(path, function_instance_attrs, False)
1.268 + self.write_structure(f_decls, f_defs, encode_bound_reference(path), table_name, structure_size, structure)
1.269 +
1.270 + # A normal function.
1.271 +
1.272 + structure = self.populate_function(path, function_instance_attrs, False)
1.273 + self.write_structure(f_decls, f_defs, path, table_name, structure_size, structure)
1.274 +
1.275 + # Write function declarations.
1.276 + # Signature: __attr <name>(__attr[]);
1.277 +
1.278 + print >>f_signatures, "__attr %s(__attr args[]);" % encode_function_pointer(path)
1.279 +
1.280 + # Write parameter table.
1.281 +
1.282 + self.make_parameter_table(f_decls, f_defs, path, path)
1.283 +
1.284 + # Output more boilerplate.
1.285 +
1.286 + print >>f_consts, """\
1.287 +
1.288 +#endif /* __PROGCONSTS_H__ */"""
1.289 +
1.290 + print >>f_decls, """\
1.291 +
1.292 +#define __FUNCTION_TYPE %s
1.293 +#define __FUNCTION_INSTANCE_SIZE %s
1.294 +
1.295 +#endif /* __PROGTYPES_H__ */""" % (
1.296 + encode_path(self.function_type),
1.297 + encode_size(self.structure_size_prefixes["<instance>"], self.function_type)
1.298 + )
1.299 +
1.300 + print >>f_signatures, """\
1.301 +
1.302 +#endif /* __MAIN_H__ */"""
1.303 +
1.304 + finally:
1.305 + f_consts.close()
1.306 + f_defs.close()
1.307 + f_decls.close()
1.308 + f_signatures.close()
1.309 + f_code.close()
1.310 +
1.311 + def make_parameter_table(self, f_decls, f_defs, path, function_path):
1.312 +
1.313 + """
1.314 + Write parameter table details to 'f_decls' (to declare a table) and to
1.315 + 'f_defs' (to define the contents) for the function with the given
1.316 + 'path', using 'function_path' to obtain the parameter details. The
1.317 + latter two arguments may differ when describing an instantiator using
1.318 + the details of an initialiser.
1.319 + """
1.320 +
1.321 + table = []
1.322 + table_name = encode_tablename("Function", path)
1.323 + structure_size = encode_size("pmax", path)
1.324 + self.populate_parameter_table(function_path, table)
1.325 + self.write_parameter_table(f_decls, f_defs, table_name, structure_size, table)
1.326 +
1.327 + def write_size_constants(self, f_consts, size_prefix, sizes, padding):
1.328 +
1.329 + """
1.330 + Write size constants to 'f_consts' for the given 'size_prefix', using
1.331 + the 'sizes' dictionary to populate the definition, adding the given
1.332 + 'padding' to the basic sizes.
1.333 + """
1.334 +
1.335 + print >>f_consts, "enum %s {" % encode_size(size_prefix)
1.336 + first = True
1.337 + for path, size in sizes.items():
1.338 + if not first:
1.339 + print >>f_consts, ","
1.340 + else:
1.341 + first = False
1.342 + f_consts.write(" %s = %d" % (encode_size(size_prefix, path), size + padding))
1.343 + print >>f_consts, "\n };"
1.344 +
1.345 + def write_code_constants(self, f_consts, attrnames, locations):
1.346 +
1.347 + """
1.348 + Write code constants to 'f_consts' for the given 'attrnames' and
1.349 + attribute 'locations'.
1.350 + """
1.351 +
1.352 + print >>f_consts, "enum %s {" % encode_symbol("code")
1.353 + first = True
1.354 + for i, attrname in enumerate(attrnames):
1.355 + if not first:
1.356 + print >>f_consts, ","
1.357 + else:
1.358 + first = False
1.359 + f_consts.write(" %s = %d" % (encode_symbol("code", attrname), i))
1.360 + print >>f_consts, "\n };"
1.361 +
1.362 + print >>f_consts, "enum %s {" % encode_symbol("pos")
1.363 + first = True
1.364 + for i, attrnames in enumerate(locations):
1.365 + for attrname in attrnames:
1.366 + if not first:
1.367 + print >>f_consts, ","
1.368 + else:
1.369 + first = False
1.370 + f_consts.write(" %s = %d" % (encode_symbol("pos", attrname), i))
1.371 + print >>f_consts, "\n };"
1.372 +
1.373 + def write_table(self, f_decls, f_defs, table_name, structure_size, table):
1.374 +
1.375 + """
1.376 + Write the declarations to 'f_decls' and definitions to 'f_defs' for
1.377 + the object having the given 'table_name' and the given 'structure_size',
1.378 + with 'table' details used to populate the definition.
1.379 + """
1.380 +
1.381 + print >>f_decls, "extern const __table %s;\n" % table_name
1.382 +
1.383 + # Write the corresponding definition.
1.384 +
1.385 + print >>f_defs, "const __table %s = {\n %s,\n {\n %s\n }\n };\n" % (
1.386 + table_name, structure_size,
1.387 + ",\n ".join(table))
1.388 +
1.389 + def write_parameter_table(self, f_decls, f_defs, table_name, structure_size, table):
1.390 +
1.391 + """
1.392 + Write the declarations to 'f_decls' and definitions to 'f_defs' for
1.393 + the object having the given 'table_name' and the given 'structure_size',
1.394 + with 'table' details used to populate the definition.
1.395 + """
1.396 +
1.397 + print >>f_decls, "extern const __ptable %s;\n" % table_name
1.398 +
1.399 + # Write the corresponding definition.
1.400 +
1.401 + print >>f_defs, "const __ptable %s = {\n %s,\n {\n %s\n }\n };\n" % (
1.402 + table_name, structure_size,
1.403 + ",\n ".join([("{%s, %s}" % t) for t in table]))
1.404 +
1.405 + def write_structure(self, f_decls, f_defs, path, table_name, structure_size, structure):
1.406 +
1.407 + """
1.408 + Write the declarations to 'f_decls' and definitions to 'f_defs' for
1.409 + the object having the given 'path', the given 'table_name', and the
1.410 + given 'structure_size', with 'structure' details used to populate the
1.411 + definition.
1.412 + """
1.413 +
1.414 + print >>f_decls, "extern __obj %s;\n" % encode_path(path)
1.415 +
1.416 + # Write an instance-specific type definition for instances of classes.
1.417 + # See: templates/types.h
1.418 +
1.419 + print >>f_decls, """\
1.420 +typedef struct {
1.421 + const __table * table;
1.422 + unsigned int pos;
1.423 + __attr attrs[%s];
1.424 +} %s;
1.425 +""" % (structure_size, encode_symbol("obj", path))
1.426 +
1.427 + # Write the corresponding definition.
1.428 +
1.429 + print >>f_defs, "__obj %s = {\n &%s,\n %s,\n {\n %s\n }};\n" % (
1.430 + encode_path(path), table_name, encode_symbol("pos", path),
1.431 + ",\n ".join(structure))
1.432 +
1.433 + def get_parameters(self, ref):
1.434 + return self.importer.function_parameters[ref.get_origin()]
1.435 +
1.436 + def get_argument_limits(self, path):
1.437 + parameters = self.importer.function_parameters[path]
1.438 + defaults = self.importer.function_defaults.get(path)
1.439 + return len(parameters) - (defaults and len(defaults) or 0), len(parameters)
1.440 +
1.441 + def get_attribute_names(self, indexes):
1.442 +
1.443 + """
1.444 + Given a list of attribute table 'indexes', return a list of attribute
1.445 + names.
1.446 + """
1.447 +
1.448 + all_attrnames = self.optimiser.all_attrnames
1.449 + attrnames = []
1.450 + for i in indexes:
1.451 + if i is None:
1.452 + attrnames.append(None)
1.453 + else:
1.454 + attrnames.append(all_attrnames[i])
1.455 + return attrnames
1.456 +
1.457 + def get_static_attributes(self, kind, name, attrnames):
1.458 +
1.459 + """
1.460 + Return a mapping of attribute names to paths for attributes belonging
1.461 + to objects of the given 'kind' (being "<class>" or "<module>") with
1.462 + the given 'name' and supporting the given 'attrnames'.
1.463 + """
1.464 +
1.465 + attrs = {}
1.466 +
1.467 + for attrname in attrnames:
1.468 + if attrname is None:
1.469 + continue
1.470 + if kind == "<class>":
1.471 + path = self.importer.all_class_attrs[name][attrname]
1.472 + elif kind == "<module>":
1.473 + path = "%s.%s" % (name, attrname)
1.474 + else:
1.475 + continue
1.476 +
1.477 + # The module may be hidden.
1.478 +
1.479 + attr = self.importer.get_object(path)
1.480 + if not attr:
1.481 + module = self.importer.hidden.get(path)
1.482 + if module:
1.483 + attr = Reference(module.name, "<module>")
1.484 + attrs[attrname] = attr
1.485 +
1.486 + return attrs
1.487 +
1.488 + def get_instance_attributes(self, name, attrnames):
1.489 +
1.490 + """
1.491 + Return a mapping of attribute names to references for attributes
1.492 + belonging to instances of the class with the given 'name', where the
1.493 + given 'attrnames' are supported.
1.494 + """
1.495 +
1.496 + consts = self.importer.all_instance_attr_constants[name]
1.497 + attrs = {}
1.498 + for attrname in attrnames:
1.499 + if attrname is None:
1.500 + continue
1.501 + const = consts.get(attrname)
1.502 + attrs[attrname] = const or Reference("<var>", "%s.%s" % (name, attrname))
1.503 + return attrs
1.504 +
1.505 + def populate_table(self, key, table):
1.506 +
1.507 + """
1.508 + Traverse the attributes in the determined order for the structure having
1.509 + the given 'key', adding entries to the attribute 'table'.
1.510 + """
1.511 +
1.512 + for attrname in self.optimiser.structures[key]:
1.513 +
1.514 + # Handle gaps in the structure.
1.515 +
1.516 + if attrname is None:
1.517 + table.append("0")
1.518 + else:
1.519 + table.append(encode_symbol("code", attrname))
1.520 +
1.521 + def populate_parameter_table(self, key, table):
1.522 +
1.523 + """
1.524 + Traverse the parameters in the determined order for the structure having
1.525 + the given 'key', adding entries to the attribute 'table'.
1.526 + """
1.527 +
1.528 + for value in self.optimiser.parameters[key]:
1.529 +
1.530 + # Handle gaps in the structure.
1.531 +
1.532 + if value is None:
1.533 + table.append(("0", "0"))
1.534 + else:
1.535 + name, pos = value
1.536 + table.append((encode_symbol("pcode", name), pos))
1.537 +
1.538 + def populate_function(self, path, function_instance_attrs, unbound=False):
1.539 +
1.540 + """
1.541 + Populate a structure for the function with the given 'path'. The given
1.542 + 'attrs' provide the instance attributes, and if 'unbound' is set to a
1.543 + true value, an unbound method structure is produced (as opposed to a
1.544 + callable bound method structure).
1.545 + """
1.546 +
1.547 + cls = self.function_type
1.548 + structure = []
1.549 + self.populate_structure(Reference("<instance>", cls), function_instance_attrs, "<instance>", structure, unbound)
1.550 +
1.551 + # Append default members.
1.552 +
1.553 + self.append_defaults(path, structure)
1.554 + return structure
1.555 +
1.556 + def populate_structure(self, ref, attrs, kind, structure, unbound=False):
1.557 +
1.558 + """
1.559 + Traverse the attributes in the determined order for the structure having
1.560 + the given 'ref' whose members are provided by the 'attrs' mapping, in a
1.561 + structure of the given 'kind', adding entries to the object 'structure'.
1.562 + If 'unbound' is set to a true value, an unbound method function pointer
1.563 + will be employed, with a reference to the bound method incorporated into
1.564 + the special __fn__ attribute.
1.565 + """
1.566 +
1.567 + origin = ref.get_origin()
1.568 +
1.569 + for attrname in self.optimiser.structures[ref]:
1.570 +
1.571 + # Handle gaps in the structure.
1.572 +
1.573 + if attrname is None:
1.574 + structure.append("{0, 0}")
1.575 +
1.576 + # Handle non-constant and constant members.
1.577 +
1.578 + else:
1.579 + attr = attrs[attrname]
1.580 +
1.581 + if attrname == "__fn__":
1.582 +
1.583 + # Provide bound method references and the unbound function
1.584 + # pointer if populating methods in a class.
1.585 +
1.586 + bound_attr = None
1.587 +
1.588 + # Classes offer instantiators.
1.589 +
1.590 + if kind == "<class>":
1.591 + attr = encode_instantiator_pointer(attr)
1.592 +
1.593 + # Methods offers references to bound versions and an unbound
1.594 + # method function.
1.595 +
1.596 + elif unbound:
1.597 + bound_attr = encode_bound_reference(attr)
1.598 + attr = "__unbound_method"
1.599 +
1.600 + # Other functions just offer function pointers.
1.601 +
1.602 + else:
1.603 + attr = encode_function_pointer(attr)
1.604 +
1.605 + structure.append("{%s, .fn=%s}" % (bound_attr and ".b=%s" % bound_attr or "0", attr))
1.606 + continue
1.607 +
1.608 + elif attrname == "__args__":
1.609 + structure.append("{.min=%s, .ptable=%s}" % (attr, encode_tablename("Function", origin)))
1.610 + continue
1.611 +
1.612 + structure.append(self.encode_member(origin, attrname, attr, kind))
1.613 +
1.614 + def encode_member(self, path, name, ref, structure_type):
1.615 +
1.616 + """
1.617 + Encode within the structure provided by 'path', the member whose 'name'
1.618 + provides 'ref', within the given 'structure_type'.
1.619 + """
1.620 +
1.621 + kind = ref.get_kind()
1.622 + origin = ref.get_origin()
1.623 +
1.624 + # References to constant literals.
1.625 +
1.626 + if kind == "<instance>":
1.627 + attr_path = "%s.%s" % (path, name)
1.628 +
1.629 + # Obtain a constant value directly assigned to the attribute.
1.630 +
1.631 + if self.optimiser.constant_numbers.has_key(attr_path):
1.632 + constant_number = self.optimiser.constant_numbers[attr_path]
1.633 + constant_value = "const%d" % constant_number
1.634 + return "{&%s, &%s} /* %s */" % (constant_value, constant_value, name)
1.635 +
1.636 + # General undetermined members.
1.637 +
1.638 + if kind in ("<var>", "<instance>"):
1.639 + return "{0, 0} /* %s */" % name
1.640 +
1.641 + # Set the context depending on the kind of attribute.
1.642 + # For methods: {&<path>, &<attr>}
1.643 + # For other attributes: {&<attr>, &<attr>}
1.644 +
1.645 + else:
1.646 + context = (kind == "<function>" and structure_type == "<class>" and \
1.647 + "&%s" % encode_path(path) or "0") or \
1.648 + kind == "<instance>" and "&%s" % encode_path(origin) or "0"
1.649 + return "{%s, &%s}" % (context, encode_path(origin))
1.650 +
1.651 + def append_defaults(self, path, structure):
1.652 +
1.653 + """
1.654 + For the given 'path', append default parameter members to the given
1.655 + 'structure'.
1.656 + """
1.657 +
1.658 + for name, default in self.importer.function_defaults.get(path):
1.659 + structure.append(self.encode_member(path, name, default, "<instance>"))
1.660 +
1.661 + def write_instantiator(self, f_code, path, init_ref):
1.662 +
1.663 + """
1.664 + Write an instantiator to 'f_code' for instances of the class with the
1.665 + given 'path', with 'init_ref' as the initialiser function reference.
1.666 +
1.667 + NOTE: This also needs to initialise any __fn__ and __args__ members
1.668 + NOTE: where __call__ is provided by the class.
1.669 + """
1.670 +
1.671 + parameters = self.get_parameters(init_ref)
1.672 + arg_copy = "memcpy(&__tmp_args[1], args, %d * sizeof(__attr));" % (len(parameters) - 1)
1.673 +
1.674 + print >>f_code, """\
1.675 +__attr %s(__attr args[])
1.676 +{
1.677 + __attr __tmp_args[%d];
1.678 + __tmp_args[0] = __new(&%s, &%s, sizeof(%s));
1.679 + %s
1.680 + %s(__tmp_args);
1.681 + return __tmp_args[0];
1.682 +}
1.683 +""" % (
1.684 + encode_instantiator_pointer(path),
1.685 + len(parameters),
1.686 + encode_tablename("Instance", path), encode_path(path), encode_symbol("obj", path),
1.687 + len(parameters) - 1 and arg_copy or "",
1.688 + encode_function_pointer(init_ref.get_origin())
1.689 + )
1.690 +
1.691 +def encode_size(table_type, path=None):
1.692 + return "__%ssize%s" % (table_type, path and "_%s" % encode_path(path) or "")
1.693 +
1.694 +def encode_tablename(table_type, path):
1.695 + return "__%sTable_%s" % (table_type, encode_path(path))
1.696 +
1.697 +# vim: tabstop=4 expandtab shiftwidth=4