2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/generator.py Mon Oct 24 21:18:10 2016 +0200
2.3 @@ -0,0 +1,694 @@
2.4 +#!/usr/bin/env python
2.5 +
2.6 +"""
2.7 +Generate C code from object layouts and other deduced information.
2.8 +
2.9 +Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>
2.10 +
2.11 +This program is free software; you can redistribute it and/or modify it under
2.12 +the terms of the GNU General Public License as published by the Free Software
2.13 +Foundation; either version 3 of the License, or (at your option) any later
2.14 +version.
2.15 +
2.16 +This program is distributed in the hope that it will be useful, but WITHOUT
2.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
2.19 +details.
2.20 +
2.21 +You should have received a copy of the GNU General Public License along with
2.22 +this program. If not, see <http://www.gnu.org/licenses/>.
2.23 +"""
2.24 +
2.25 +from common import CommonOutput
2.26 +from encoders import encode_bound_reference, encode_function_pointer, \
2.27 + encode_instantiator_pointer, encode_path, encode_symbol
2.28 +from os import listdir
2.29 +from os.path import isdir, join, split
2.30 +from referencing import Reference
2.31 +
2.32 +def copy(source, target):
2.33 +
2.34 + "Copy a text file from 'source' to 'target'."
2.35 +
2.36 + if isdir(target):
2.37 + target = join(target, split(source)[-1])
2.38 + infile = open(source)
2.39 + outfile = open(target, "w")
2.40 + try:
2.41 + outfile.write(infile.read())
2.42 + finally:
2.43 + outfile.close()
2.44 + infile.close()
2.45 +
2.46 +class Generator(CommonOutput):
2.47 +
2.48 + "A code generator."
2.49 +
2.50 + function_type = "__builtins__.core.function"
2.51 +
2.52 + table_name_prefixes = {
2.53 + "<class>" : "Class",
2.54 + "<module>" : "Module",
2.55 + "<instance>" : "Instance"
2.56 + }
2.57 +
2.58 + structure_size_prefixes = {
2.59 + "<class>" : "c",
2.60 + "<module>" : "m",
2.61 + "<instance>" : "i"
2.62 + }
2.63 +
2.64 + def __init__(self, importer, optimiser, output):
2.65 + self.importer = importer
2.66 + self.optimiser = optimiser
2.67 + self.output = output
2.68 +
2.69 + def to_output(self):
2.70 +
2.71 + "Write the generated code."
2.72 +
2.73 + self.check_output()
2.74 + self.write_structures()
2.75 + self.copy_templates()
2.76 +
2.77 + def copy_templates(self):
2.78 +
2.79 + "Copy template files to the generated output directory."
2.80 +
2.81 + templates = join(split(__file__)[0], "templates")
2.82 +
2.83 + for filename in listdir(templates):
2.84 + copy(join(templates, filename), self.output)
2.85 +
2.86 + def write_structures(self):
2.87 +
2.88 + "Write structures used by the program."
2.89 +
2.90 + f_consts = open(join(self.output, "progconsts.h"), "w")
2.91 + f_defs = open(join(self.output, "progtypes.c"), "w")
2.92 + f_decls = open(join(self.output, "progtypes.h"), "w")
2.93 + f_signatures = open(join(self.output, "main.h"), "w")
2.94 + f_code = open(join(self.output, "main.c"), "w")
2.95 +
2.96 + try:
2.97 + # Output boilerplate.
2.98 +
2.99 + print >>f_consts, """\
2.100 +#ifndef __PROGCONSTS_H__
2.101 +#define __PROGCONSTS_H__
2.102 +"""
2.103 + print >>f_decls, """\
2.104 +#ifndef __PROGTYPES_H__
2.105 +#define __PROGTYPES_H__
2.106 +
2.107 +#include "progconsts.h"
2.108 +#include "types.h"
2.109 +"""
2.110 + print >>f_defs, """\
2.111 +#include "progtypes.h"
2.112 +#include "main.h"
2.113 +"""
2.114 + print >>f_signatures, """\
2.115 +#ifndef __MAIN_H__
2.116 +#define __MAIN_H__
2.117 +
2.118 +#include "types.h"
2.119 +"""
2.120 + print >>f_code, """\
2.121 +#include <string.h>
2.122 +#include "types.h"
2.123 +#include "ops.h"
2.124 +#include "progconsts.h"
2.125 +#include "progtypes.h"
2.126 +#include "progops.h"
2.127 +#include "main.h"
2.128 +"""
2.129 +
2.130 + # Generate structure size data.
2.131 +
2.132 + size_tables = {}
2.133 +
2.134 + for kind in ["<class>", "<module>", "<instance>"]:
2.135 + size_tables[kind] = {}
2.136 +
2.137 + for ref, structure in self.optimiser.structures.items():
2.138 + size_tables[ref.get_kind()][ref.get_origin()] = len(structure)
2.139 +
2.140 + size_tables = size_tables.items()
2.141 + size_tables.sort()
2.142 +
2.143 + for kind, sizes in size_tables:
2.144 + self.write_size_constants(f_consts, self.structure_size_prefixes[kind], sizes, 0)
2.145 +
2.146 + # Generate parameter table size data.
2.147 +
2.148 + min_sizes = {}
2.149 + max_sizes = {}
2.150 +
2.151 + for path, parameters in self.optimiser.parameters.items():
2.152 + argmin, argmax = self.get_argument_limits(path)
2.153 + min_sizes[path] = argmin
2.154 + max_sizes[path] = argmax
2.155 +
2.156 + # Record instantiator limits.
2.157 +
2.158 + if path.endswith(".__init__"):
2.159 + path = path[:-len(".__init__")]
2.160 + min_sizes[path] = argmin - 1
2.161 + max_sizes[path] = argmax - 1
2.162 +
2.163 + self.write_size_constants(f_consts, "pmin", min_sizes, 0)
2.164 + self.write_size_constants(f_consts, "pmax", max_sizes, 0)
2.165 +
2.166 + # Generate attribute codes.
2.167 +
2.168 + self.write_code_constants(f_consts, self.optimiser.all_attrnames, self.optimiser.locations)
2.169 +
2.170 + # Generate table and structure data.
2.171 +
2.172 + function_instance_attrs = None
2.173 + objects = self.optimiser.attr_table.items()
2.174 + objects.sort()
2.175 +
2.176 + for ref, indexes in objects:
2.177 + attrnames = self.get_attribute_names(indexes)
2.178 +
2.179 + kind = ref.get_kind()
2.180 + path = ref.get_origin()
2.181 + table_name = encode_tablename(self.table_name_prefixes[kind], path)
2.182 + structure_size = encode_size(self.structure_size_prefixes[kind], path)
2.183 +
2.184 + # Generate structures for classes and modules.
2.185 +
2.186 + if kind != "<instance>":
2.187 + structure = []
2.188 + attrs = self.get_static_attributes(kind, path, attrnames)
2.189 +
2.190 + # Set a special instantiator on the class.
2.191 +
2.192 + if kind == "<class>":
2.193 + attrs["__fn__"] = path
2.194 + attrs["__args__"] = encode_size("pmin", path)
2.195 +
2.196 + # Write instantiator declarations based on the
2.197 + # applicable initialiser.
2.198 +
2.199 + init_ref = attrs["__init__"]
2.200 +
2.201 + # Signature: __attr __new_<name>(__attr[]);
2.202 +
2.203 + print >>f_signatures, "__attr %s(__attr[]);" % encode_instantiator_pointer(path)
2.204 +
2.205 + # Write instantiator definitions.
2.206 +
2.207 + self.write_instantiator(f_code, path, init_ref)
2.208 +
2.209 + # Write parameter table.
2.210 +
2.211 + self.make_parameter_table(f_decls, f_defs, path, init_ref.get_origin())
2.212 +
2.213 + self.populate_structure(Reference(kind, path), attrs, kind, structure)
2.214 + self.write_structure(f_decls, f_defs, path, table_name, structure_size, structure)
2.215 +
2.216 + # Record function instance details for function generation below.
2.217 +
2.218 + else:
2.219 + attrs = self.get_instance_attributes(path, attrnames)
2.220 + if path == self.function_type:
2.221 + function_instance_attrs = attrs
2.222 +
2.223 + # Write a table for all objects.
2.224 +
2.225 + table = []
2.226 + self.populate_table(Reference(kind, path), table)
2.227 + self.write_table(f_decls, f_defs, table_name, structure_size, table)
2.228 +
2.229 + # Generate function instances.
2.230 +
2.231 + functions = set()
2.232 +
2.233 + for ref in self.importer.objects.values():
2.234 + if ref.has_kind("<function>"):
2.235 + functions.add(ref.get_origin())
2.236 +
2.237 + functions = list(functions)
2.238 + functions.sort()
2.239 +
2.240 + for path in functions:
2.241 + cls = self.function_type
2.242 + table_name = encode_tablename("Instance", cls)
2.243 + structure_size = encode_size(self.structure_size_prefixes["<instance>"], cls)
2.244 +
2.245 + # Set a special callable attribute on the instance.
2.246 +
2.247 + function_instance_attrs["__fn__"] = path
2.248 + function_instance_attrs["__args__"] = encode_size("pmin", path)
2.249 +
2.250 + # Produce two structures where a method is involved.
2.251 +
2.252 + ref = self.importer.get_object(path)
2.253 + parent_ref = self.importer.get_object(ref.parent())
2.254 + parent_kind = parent_ref and parent_ref.get_kind()
2.255 +
2.256 + # Populate and write each structure.
2.257 +
2.258 + if parent_kind == "<class>":
2.259 +
2.260 + # An unbound version of a method.
2.261 +
2.262 + structure = self.populate_function(path, function_instance_attrs, True)
2.263 + self.write_structure(f_decls, f_defs, path, table_name, structure_size, structure)
2.264 +
2.265 + # A bound version of a method.
2.266 +
2.267 + structure = self.populate_function(path, function_instance_attrs, False)
2.268 + self.write_structure(f_decls, f_defs, encode_bound_reference(path), table_name, structure_size, structure)
2.269 +
2.270 + # A normal function.
2.271 +
2.272 + structure = self.populate_function(path, function_instance_attrs, False)
2.273 + self.write_structure(f_decls, f_defs, path, table_name, structure_size, structure)
2.274 +
2.275 + # Write function declarations.
2.276 + # Signature: __attr <name>(__attr[]);
2.277 +
2.278 + print >>f_signatures, "__attr %s(__attr args[]);" % encode_function_pointer(path)
2.279 +
2.280 + # Write parameter table.
2.281 +
2.282 + self.make_parameter_table(f_decls, f_defs, path, path)
2.283 +
2.284 + # Output more boilerplate.
2.285 +
2.286 + print >>f_consts, """\
2.287 +
2.288 +#endif /* __PROGCONSTS_H__ */"""
2.289 +
2.290 + print >>f_decls, """\
2.291 +
2.292 +#define __FUNCTION_TYPE %s
2.293 +#define __FUNCTION_INSTANCE_SIZE %s
2.294 +
2.295 +#endif /* __PROGTYPES_H__ */""" % (
2.296 + encode_path(self.function_type),
2.297 + encode_size(self.structure_size_prefixes["<instance>"], self.function_type)
2.298 + )
2.299 +
2.300 + print >>f_signatures, """\
2.301 +
2.302 +#endif /* __MAIN_H__ */"""
2.303 +
2.304 + finally:
2.305 + f_consts.close()
2.306 + f_defs.close()
2.307 + f_decls.close()
2.308 + f_signatures.close()
2.309 + f_code.close()
2.310 +
2.311 + def make_parameter_table(self, f_decls, f_defs, path, function_path):
2.312 +
2.313 + """
2.314 + Write parameter table details to 'f_decls' (to declare a table) and to
2.315 + 'f_defs' (to define the contents) for the function with the given
2.316 + 'path', using 'function_path' to obtain the parameter details. The
2.317 + latter two arguments may differ when describing an instantiator using
2.318 + the details of an initialiser.
2.319 + """
2.320 +
2.321 + table = []
2.322 + table_name = encode_tablename("Function", path)
2.323 + structure_size = encode_size("pmax", path)
2.324 + self.populate_parameter_table(function_path, table)
2.325 + self.write_parameter_table(f_decls, f_defs, table_name, structure_size, table)
2.326 +
2.327 + def write_size_constants(self, f_consts, size_prefix, sizes, padding):
2.328 +
2.329 + """
2.330 + Write size constants to 'f_consts' for the given 'size_prefix', using
2.331 + the 'sizes' dictionary to populate the definition, adding the given
2.332 + 'padding' to the basic sizes.
2.333 + """
2.334 +
2.335 + print >>f_consts, "enum %s {" % encode_size(size_prefix)
2.336 + first = True
2.337 + for path, size in sizes.items():
2.338 + if not first:
2.339 + print >>f_consts, ","
2.340 + else:
2.341 + first = False
2.342 + f_consts.write(" %s = %d" % (encode_size(size_prefix, path), size + padding))
2.343 + print >>f_consts, "\n };"
2.344 +
2.345 + def write_code_constants(self, f_consts, attrnames, locations):
2.346 +
2.347 + """
2.348 + Write code constants to 'f_consts' for the given 'attrnames' and
2.349 + attribute 'locations'.
2.350 + """
2.351 +
2.352 + print >>f_consts, "enum %s {" % encode_symbol("code")
2.353 + first = True
2.354 + for i, attrname in enumerate(attrnames):
2.355 + if not first:
2.356 + print >>f_consts, ","
2.357 + else:
2.358 + first = False
2.359 + f_consts.write(" %s = %d" % (encode_symbol("code", attrname), i))
2.360 + print >>f_consts, "\n };"
2.361 +
2.362 + print >>f_consts, "enum %s {" % encode_symbol("pos")
2.363 + first = True
2.364 + for i, attrnames in enumerate(locations):
2.365 + for attrname in attrnames:
2.366 + if not first:
2.367 + print >>f_consts, ","
2.368 + else:
2.369 + first = False
2.370 + f_consts.write(" %s = %d" % (encode_symbol("pos", attrname), i))
2.371 + print >>f_consts, "\n };"
2.372 +
2.373 + def write_table(self, f_decls, f_defs, table_name, structure_size, table):
2.374 +
2.375 + """
2.376 + Write the declarations to 'f_decls' and definitions to 'f_defs' for
2.377 + the object having the given 'table_name' and the given 'structure_size',
2.378 + with 'table' details used to populate the definition.
2.379 + """
2.380 +
2.381 + print >>f_decls, "extern const __table %s;\n" % table_name
2.382 +
2.383 + # Write the corresponding definition.
2.384 +
2.385 + print >>f_defs, "const __table %s = {\n %s,\n {\n %s\n }\n };\n" % (
2.386 + table_name, structure_size,
2.387 + ",\n ".join(table))
2.388 +
2.389 + def write_parameter_table(self, f_decls, f_defs, table_name, structure_size, table):
2.390 +
2.391 + """
2.392 + Write the declarations to 'f_decls' and definitions to 'f_defs' for
2.393 + the object having the given 'table_name' and the given 'structure_size',
2.394 + with 'table' details used to populate the definition.
2.395 + """
2.396 +
2.397 + print >>f_decls, "extern const __ptable %s;\n" % table_name
2.398 +
2.399 + # Write the corresponding definition.
2.400 +
2.401 + print >>f_defs, "const __ptable %s = {\n %s,\n {\n %s\n }\n };\n" % (
2.402 + table_name, structure_size,
2.403 + ",\n ".join([("{%s, %s}" % t) for t in table]))
2.404 +
2.405 + def write_structure(self, f_decls, f_defs, path, table_name, structure_size, structure):
2.406 +
2.407 + """
2.408 + Write the declarations to 'f_decls' and definitions to 'f_defs' for
2.409 + the object having the given 'path', the given 'table_name', and the
2.410 + given 'structure_size', with 'structure' details used to populate the
2.411 + definition.
2.412 + """
2.413 +
2.414 + print >>f_decls, "extern __obj %s;\n" % encode_path(path)
2.415 +
2.416 + # Write an instance-specific type definition for instances of classes.
2.417 + # See: templates/types.h
2.418 +
2.419 + print >>f_decls, """\
2.420 +typedef struct {
2.421 + const __table * table;
2.422 + unsigned int pos;
2.423 + __attr attrs[%s];
2.424 +} %s;
2.425 +""" % (structure_size, encode_symbol("obj", path))
2.426 +
2.427 + # Write the corresponding definition.
2.428 +
2.429 + print >>f_defs, "__obj %s = {\n &%s,\n %s,\n {\n %s\n }};\n" % (
2.430 + encode_path(path), table_name, encode_symbol("pos", path),
2.431 + ",\n ".join(structure))
2.432 +
2.433 + def get_parameters(self, ref):
2.434 + return self.importer.function_parameters[ref.get_origin()]
2.435 +
2.436 + def get_argument_limits(self, path):
2.437 + parameters = self.importer.function_parameters[path]
2.438 + defaults = self.importer.function_defaults.get(path)
2.439 + return len(parameters) - (defaults and len(defaults) or 0), len(parameters)
2.440 +
2.441 + def get_attribute_names(self, indexes):
2.442 +
2.443 + """
2.444 + Given a list of attribute table 'indexes', return a list of attribute
2.445 + names.
2.446 + """
2.447 +
2.448 + all_attrnames = self.optimiser.all_attrnames
2.449 + attrnames = []
2.450 + for i in indexes:
2.451 + if i is None:
2.452 + attrnames.append(None)
2.453 + else:
2.454 + attrnames.append(all_attrnames[i])
2.455 + return attrnames
2.456 +
2.457 + def get_static_attributes(self, kind, name, attrnames):
2.458 +
2.459 + """
2.460 + Return a mapping of attribute names to paths for attributes belonging
2.461 + to objects of the given 'kind' (being "<class>" or "<module>") with
2.462 + the given 'name' and supporting the given 'attrnames'.
2.463 + """
2.464 +
2.465 + attrs = {}
2.466 +
2.467 + for attrname in attrnames:
2.468 + if attrname is None:
2.469 + continue
2.470 + if kind == "<class>":
2.471 + path = self.importer.all_class_attrs[name][attrname]
2.472 + elif kind == "<module>":
2.473 + path = "%s.%s" % (name, attrname)
2.474 + else:
2.475 + continue
2.476 +
2.477 + # The module may be hidden.
2.478 +
2.479 + attr = self.importer.get_object(path)
2.480 + if not attr:
2.481 + module = self.importer.hidden.get(path)
2.482 + if module:
2.483 + attr = Reference(module.name, "<module>")
2.484 + attrs[attrname] = attr
2.485 +
2.486 + return attrs
2.487 +
2.488 + def get_instance_attributes(self, name, attrnames):
2.489 +
2.490 + """
2.491 + Return a mapping of attribute names to references for attributes
2.492 + belonging to instances of the class with the given 'name', where the
2.493 + given 'attrnames' are supported.
2.494 + """
2.495 +
2.496 + consts = self.importer.all_instance_attr_constants[name]
2.497 + attrs = {}
2.498 + for attrname in attrnames:
2.499 + if attrname is None:
2.500 + continue
2.501 + const = consts.get(attrname)
2.502 + attrs[attrname] = const or Reference("<var>", "%s.%s" % (name, attrname))
2.503 + return attrs
2.504 +
2.505 + def populate_table(self, key, table):
2.506 +
2.507 + """
2.508 + Traverse the attributes in the determined order for the structure having
2.509 + the given 'key', adding entries to the attribute 'table'.
2.510 + """
2.511 +
2.512 + for attrname in self.optimiser.structures[key]:
2.513 +
2.514 + # Handle gaps in the structure.
2.515 +
2.516 + if attrname is None:
2.517 + table.append("0")
2.518 + else:
2.519 + table.append(encode_symbol("code", attrname))
2.520 +
2.521 + def populate_parameter_table(self, key, table):
2.522 +
2.523 + """
2.524 + Traverse the parameters in the determined order for the structure having
2.525 + the given 'key', adding entries to the attribute 'table'.
2.526 + """
2.527 +
2.528 + for value in self.optimiser.parameters[key]:
2.529 +
2.530 + # Handle gaps in the structure.
2.531 +
2.532 + if value is None:
2.533 + table.append(("0", "0"))
2.534 + else:
2.535 + name, pos = value
2.536 + table.append((encode_symbol("pcode", name), pos))
2.537 +
2.538 + def populate_function(self, path, function_instance_attrs, unbound=False):
2.539 +
2.540 + """
2.541 + Populate a structure for the function with the given 'path'. The given
2.542 + 'attrs' provide the instance attributes, and if 'unbound' is set to a
2.543 + true value, an unbound method structure is produced (as opposed to a
2.544 + callable bound method structure).
2.545 + """
2.546 +
2.547 + cls = self.function_type
2.548 + structure = []
2.549 + self.populate_structure(Reference("<instance>", cls), function_instance_attrs, "<instance>", structure, unbound)
2.550 +
2.551 + # Append default members.
2.552 +
2.553 + self.append_defaults(path, structure)
2.554 + return structure
2.555 +
2.556 + def populate_structure(self, ref, attrs, kind, structure, unbound=False):
2.557 +
2.558 + """
2.559 + Traverse the attributes in the determined order for the structure having
2.560 + the given 'ref' whose members are provided by the 'attrs' mapping, in a
2.561 + structure of the given 'kind', adding entries to the object 'structure'.
2.562 + If 'unbound' is set to a true value, an unbound method function pointer
2.563 + will be employed, with a reference to the bound method incorporated into
2.564 + the special __fn__ attribute.
2.565 + """
2.566 +
2.567 + origin = ref.get_origin()
2.568 +
2.569 + for attrname in self.optimiser.structures[ref]:
2.570 +
2.571 + # Handle gaps in the structure.
2.572 +
2.573 + if attrname is None:
2.574 + structure.append("{0, 0}")
2.575 +
2.576 + # Handle non-constant and constant members.
2.577 +
2.578 + else:
2.579 + attr = attrs[attrname]
2.580 +
2.581 + if attrname == "__fn__":
2.582 +
2.583 + # Provide bound method references and the unbound function
2.584 + # pointer if populating methods in a class.
2.585 +
2.586 + bound_attr = None
2.587 +
2.588 + # Classes offer instantiators.
2.589 +
2.590 + if kind == "<class>":
2.591 + attr = encode_instantiator_pointer(attr)
2.592 +
2.593 + # Methods offers references to bound versions and an unbound
2.594 + # method function.
2.595 +
2.596 + elif unbound:
2.597 + bound_attr = encode_bound_reference(attr)
2.598 + attr = "__unbound_method"
2.599 +
2.600 + # Other functions just offer function pointers.
2.601 +
2.602 + else:
2.603 + attr = encode_function_pointer(attr)
2.604 +
2.605 + structure.append("{%s, .fn=%s}" % (bound_attr and ".b=%s" % bound_attr or "0", attr))
2.606 + continue
2.607 +
2.608 + elif attrname == "__args__":
2.609 + structure.append("{.min=%s, .ptable=%s}" % (attr, encode_tablename("Function", origin)))
2.610 + continue
2.611 +
2.612 + structure.append(self.encode_member(origin, attrname, attr, kind))
2.613 +
2.614 + def encode_member(self, path, name, ref, structure_type):
2.615 +
2.616 + """
2.617 + Encode within the structure provided by 'path', the member whose 'name'
2.618 + provides 'ref', within the given 'structure_type'.
2.619 + """
2.620 +
2.621 + kind = ref.get_kind()
2.622 + origin = ref.get_origin()
2.623 +
2.624 + # References to constant literals.
2.625 +
2.626 + if kind == "<instance>":
2.627 + attr_path = "%s.%s" % (path, name)
2.628 +
2.629 + # Obtain a constant value directly assigned to the attribute.
2.630 +
2.631 + if self.optimiser.constant_numbers.has_key(attr_path):
2.632 + constant_number = self.optimiser.constant_numbers[attr_path]
2.633 + constant_value = "const%d" % constant_number
2.634 + return "{&%s, &%s} /* %s */" % (constant_value, constant_value, name)
2.635 +
2.636 + # General undetermined members.
2.637 +
2.638 + if kind in ("<var>", "<instance>"):
2.639 + return "{0, 0} /* %s */" % name
2.640 +
2.641 + # Set the context depending on the kind of attribute.
2.642 + # For methods: {&<path>, &<attr>}
2.643 + # For other attributes: {&<attr>, &<attr>}
2.644 +
2.645 + else:
2.646 + context = (kind == "<function>" and structure_type == "<class>" and \
2.647 + "&%s" % encode_path(path) or "0") or \
2.648 + kind == "<instance>" and "&%s" % encode_path(origin) or "0"
2.649 + return "{%s, &%s}" % (context, encode_path(origin))
2.650 +
2.651 + def append_defaults(self, path, structure):
2.652 +
2.653 + """
2.654 + For the given 'path', append default parameter members to the given
2.655 + 'structure'.
2.656 + """
2.657 +
2.658 + for name, default in self.importer.function_defaults.get(path):
2.659 + structure.append(self.encode_member(path, name, default, "<instance>"))
2.660 +
2.661 + def write_instantiator(self, f_code, path, init_ref):
2.662 +
2.663 + """
2.664 + Write an instantiator to 'f_code' for instances of the class with the
2.665 + given 'path', with 'init_ref' as the initialiser function reference.
2.666 +
2.667 + NOTE: This also needs to initialise any __fn__ and __args__ members
2.668 + NOTE: where __call__ is provided by the class.
2.669 + """
2.670 +
2.671 + parameters = self.get_parameters(init_ref)
2.672 + arg_copy = "memcpy(&__tmp_args[1], args, %d * sizeof(__attr));" % (len(parameters) - 1)
2.673 +
2.674 + print >>f_code, """\
2.675 +__attr %s(__attr args[])
2.676 +{
2.677 + __attr __tmp_args[%d];
2.678 + __tmp_args[0] = __new(&%s, &%s, sizeof(%s));
2.679 + %s
2.680 + %s(__tmp_args);
2.681 + return __tmp_args[0];
2.682 +}
2.683 +""" % (
2.684 + encode_instantiator_pointer(path),
2.685 + len(parameters),
2.686 + encode_tablename("Instance", path), encode_path(path), encode_symbol("obj", path),
2.687 + len(parameters) - 1 and arg_copy or "",
2.688 + encode_function_pointer(init_ref.get_origin())
2.689 + )
2.690 +
2.691 +def encode_size(table_type, path=None):
2.692 + return "__%ssize%s" % (table_type, path and "_%s" % encode_path(path) or "")
2.693 +
2.694 +def encode_tablename(table_type, path):
2.695 + return "__%sTable_%s" % (table_type, encode_path(path))
2.696 +
2.697 +# vim: tabstop=4 expandtab shiftwidth=4
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/templates/ops.c Mon Oct 24 21:18:10 2016 +0200
5.3 @@ -0,0 +1,212 @@
5.4 +/* Common operations. */
5.5 +
5.6 +#include "ops.h"
5.7 +#include "progconsts.h"
5.8 +#include "progtypes.h"
5.9 +
5.10 +__attr null = {0, 0};
5.11 +
5.12 +/* Direct access to functions. */
5.13 +
5.14 +__attr __load_function(__func fn)
5.15 +{
5.16 + __attr out = {0, .fn=fn};
5.17 + return out;
5.18 +}
5.19 +
5.20 +/* Direct access and manipulation of static objects. */
5.21 +
5.22 +__attr __load_static(__ref obj)
5.23 +{
5.24 + __attr out = {0, .value=obj};
5.25 + return out;
5.26 +}
5.27 +
5.28 +/* Direct retrieval operations, returning and setting attributes. */
5.29 +
5.30 +__attr __load_via_object(__ref obj, int pos)
5.31 +{
5.32 + return obj->attrs[pos];
5.33 +}
5.34 +
5.35 +__attr __load_via_class(__ref obj, int pos)
5.36 +{
5.37 + return __load_via_object(__get_class(obj), pos);
5.38 +}
5.39 +
5.40 +__attr __get_class_and_load(__ref obj, int pos)
5.41 +{
5.42 + if (!__is_instance(obj))
5.43 + return __load_via_object(obj, pos);
5.44 + else
5.45 + return __load_via_class(obj, pos);
5.46 +}
5.47 +
5.48 +/* Direct storage operations. */
5.49 +
5.50 +int __store_via_object(__ref obj, int pos, __attr value)
5.51 +{
5.52 + obj->attrs[pos] = value;
5.53 + return 1;
5.54 +}
5.55 +
5.56 +/* Introspection. */
5.57 +
5.58 +int __is_instance(__ref obj)
5.59 +{
5.60 + return obj->pos == __INSTANCEPOS;
5.61 +}
5.62 +
5.63 +__ref __get_class(__ref obj)
5.64 +{
5.65 + return __load_via_object(obj, __pos___class__).value;
5.66 +}
5.67 +
5.68 +/* Attribute testing operations. */
5.69 +
5.70 +int __test_specific_instance(__ref obj, __ref type)
5.71 +{
5.72 + return __get_class(obj) == type;
5.73 +}
5.74 +
5.75 +int __test_common_instance(__ref obj, int pos, int code)
5.76 +{
5.77 + return __HASATTR(__get_class(obj), pos, code);
5.78 +}
5.79 +
5.80 +/* Attribute testing and retrieval operations. */
5.81 +
5.82 +__attr __check_and_load_via_class(__ref obj, int pos, int code)
5.83 +{
5.84 + return __check_and_load_via_object(__get_class(obj), pos, code);
5.85 +}
5.86 +
5.87 +__attr __check_and_load_via_object(__ref obj, int pos, int code)
5.88 +{
5.89 + return __HASATTR(obj, pos, code) ? __load_via_object(obj, pos) : null;
5.90 +}
5.91 +
5.92 +__attr __check_and_load_via_any(__ref obj, int pos, int code)
5.93 +{
5.94 + __attr out = __check_and_load_via_object(obj, pos, code);
5.95 + if (out.value == 0)
5.96 + out = __check_and_load_via_class(obj, pos, code);
5.97 + return out;
5.98 +}
5.99 +
5.100 +/* Attribute testing and storage operations. */
5.101 +
5.102 +int __check_and_store_via_object(__ref obj, int pos, int code, __attr value)
5.103 +{
5.104 + if (__HASATTR(obj, pos, code))
5.105 + {
5.106 + __store_via_object(obj, pos, value);
5.107 + return 1;
5.108 + }
5.109 + return 0;
5.110 +}
5.111 +
5.112 +int __check_and_store_via_any(__ref obj, int pos, int code, __attr value)
5.113 +{
5.114 + if (__check_and_store_via_object(obj, pos, code, value))
5.115 + return 1;
5.116 + return __check_and_store_via_object(__get_class(obj), pos, code, value);
5.117 +}
5.118 +
5.119 +/* Context-related operations. */
5.120 +
5.121 +__attr __test_context(__ref context, __attr attr)
5.122 +{
5.123 + if (__is_instance(attr.context))
5.124 + return attr;
5.125 + if (__test_common_instance(context, __TYPEPOS(attr.context), __TYPECODE(attr.context)))
5.126 + return __replace_context(context, attr);
5.127 +
5.128 + /* NOTE: An error may be more appropriate. */
5.129 +
5.130 + return null;
5.131 +}
5.132 +
5.133 +__attr __replace_context(__ref context, __attr attr)
5.134 +{
5.135 + __attr out;
5.136 +
5.137 + /* Set the context. */
5.138 +
5.139 + out.context = context;
5.140 +
5.141 + /* Reference a callable version of the attribute by obtaining the bound
5.142 + method reference from the __fn__ special attribute. */
5.143 +
5.144 + out.value = __load_via_object(attr.value, __ATTRPOS(__fn__)).b;
5.145 + return out;
5.146 +}
5.147 +
5.148 +__attr __update_context(__ref context, __attr attr)
5.149 +{
5.150 + __attr out = {context, .fn=attr.fn};
5.151 + return out;
5.152 +}
5.153 +
5.154 +/* Basic structure tests. */
5.155 +
5.156 +int __WITHIN(__ref obj, int pos)
5.157 +{
5.158 + return pos < obj->table->size;
5.159 +}
5.160 +
5.161 +int __HASATTR(__ref obj, int pos, int code)
5.162 +{
5.163 + return __WITHIN(obj, pos) && (obj->table->attrs[pos] == code);
5.164 +}
5.165 +
5.166 +/* Parameter position operations. */
5.167 +
5.168 +int __HASPARAM(const __ptable *ptable, int ppos, int pcode)
5.169 +{
5.170 + __param param;
5.171 +
5.172 + if (ppos < ptable->size)
5.173 + {
5.174 + param = ptable->params[ppos];
5.175 + if (param.code == pcode)
5.176 + return param.pos;
5.177 + }
5.178 +
5.179 + return -1;
5.180 +}
5.181 +
5.182 +/* Conversions. */
5.183 +
5.184 +__attr __CONTEXT_AS_VALUE(__attr attr)
5.185 +{
5.186 + __attr out;
5.187 + out.context = attr.context;
5.188 + out.value = attr.context;
5.189 + return out;
5.190 +}
5.191 +
5.192 +/* Type testing. */
5.193 +
5.194 +int __ISFUNC(__ref obj)
5.195 +{
5.196 + return __test_specific_instance(obj, &__FUNCTION_TYPE);
5.197 +}
5.198 +
5.199 +int __ISNULL(__attr value)
5.200 +{
5.201 + /* (value.context == null.context) is superfluous */
5.202 + return (value.value == null.value);
5.203 +}
5.204 +
5.205 +/* Attribute codes and positions for type objects. */
5.206 +
5.207 +unsigned int __TYPECODE(__ref obj)
5.208 +{
5.209 + return obj->table->attrs[obj->pos];
5.210 +}
5.211 +
5.212 +unsigned int __TYPEPOS(__ref obj)
5.213 +{
5.214 + return obj->pos;
5.215 +}