Lichen

Annotated generator.py

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