Пример #1
0
    def generate_c_module(self) -> str:
        emitter = Emitter(self.context)

        self.declare_imports(self.module.imports)

        for cl in self.module.classes:
            generate_class(cl, self.module_name, emitter)

        for fn in self.module.functions:
            generate_function_declaration(fn, emitter)

        emitter.emit_line()

        self.generate_module_def(emitter)

        for fn in self.module.functions:
            emitter.emit_line()
            generate_native_function(fn, emitter)
            emitter.emit_line()
            generate_wrapper_function(fn, emitter)

        declarations = Emitter(self.context)
        declarations.emit_line('#include <Python.h>')
        declarations.emit_line('#include <CPy.h>')
        declarations.emit_line()

        for declaration in self.toposort_declarations():
            declarations.emit_lines(*declaration.body)

        return ''.join(declarations.fragments + emitter.fragments)
Пример #2
0
    def generate_c_for_modules(self) -> str:
        emitter = Emitter(self.context)

        module_irs = [module_ir for _, module_ir in self.modules]

        for module_name, module in self.modules:
            self.declare_module(module_name, emitter)
            self.declare_internal_globals(module_name, emitter)
            self.declare_imports(module.imports, emitter)

        for identifier in self.literals.values():
            self.declare_static_pyobject(identifier, emitter)

        for module in module_irs:
            for fn in module.functions:
                generate_function_declaration(fn, emitter)

        self.generate_literals(emitter)

        classes = []
        for module_name, module in self.modules:
            classes.extend([(module_name, cl) for cl in module.classes])
        # We must topo sort so that base classes are generated first.
        classes = sort_classes(classes)
        for module_name, cl in classes:
            generate_class_type_decl(cl, emitter)
        for module_name, cl in classes:
            generate_class(cl, module_name, emitter)

        emitter.emit_line()

        # Generate Python extension module definitions and module initialization functions.
        for module_name, module in self.modules:
            self.generate_module_def(emitter, module_name, module)

        for module_name, module in self.modules:
            for fn in module.functions:
                emitter.emit_line()
                generate_native_function(fn, emitter,
                                         self.source_paths[module_name],
                                         module_name)
                if fn.name != TOP_LEVEL_NAME:
                    emitter.emit_line()
                    generate_wrapper_function(fn, emitter)

        declarations = Emitter(self.context)
        declarations.emit_line('#include <Python.h>')
        declarations.emit_line('#include <CPy.h>')
        declarations.emit_line()

        for declaration in self.toposort_declarations():
            declarations.emit_lines(*declaration.body)

        for static_def in self.context.statics.values():
            declarations.emit_line(static_def)

        return ''.join(declarations.fragments + emitter.fragments)
Пример #3
0
 def test_simple(self) -> None:
     self.block.ops.append(Return(self.reg))
     fn = FuncIR('myfunc', [self.arg], IntRType(), [self.block], self.env)
     emitter = Emitter(EmitterContext())
     generate_native_function(fn, emitter)
     result = emitter.fragments
     assert_string_arrays_equal([
         'static CPyTagged CPyDef_myfunc(CPyTagged cpy_r_arg) {\n',
         'CPyL0: ;\n',
         '    return cpy_r_arg;\n',
         '}\n',
     ],
                                result,
                                msg='Generated code invalid')
Пример #4
0
 def test_simple(self) -> None:
     self.block.ops.append(Return(self.reg))
     fn = FuncIR('myfunc', None, 'mod', FuncSignature([self.arg], int_rprimitive),
                 [self.block], self.env)
     emitter = Emitter(EmitterContext(['mod']))
     generate_native_function(fn, emitter, 'prog.py', 'prog')
     result = emitter.fragments
     assert_string_arrays_equal(
         [
             'static CPyTagged CPyDef_myfunc(CPyTagged cpy_r_arg) {\n',
             'CPyL0: ;\n',
             '    return cpy_r_arg;\n',
             '}\n',
         ],
         result, msg='Generated code invalid')
Пример #5
0
 def test_register(self) -> None:
     self.temp = self.env.add_temp(IntRType())
     self.block.ops.append(LoadInt(self.temp, 5))
     fn = FuncIR('myfunc', [self.arg], ListRType(), [self.block], self.env)
     emitter = Emitter(EmitterContext())
     generate_native_function(fn, emitter)
     result = emitter.fragments
     assert_string_arrays_equal([
         'static PyObject *CPyDef_myfunc(CPyTagged cpy_r_arg) {\n',
         '    CPyTagged cpy_r_r0;\n',
         'CPyL0: ;\n',
         '    cpy_r_r0 = 10;\n',
         '}\n',
     ],
                                result,
                                msg='Generated code invalid')
Пример #6
0
 def test_register(self) -> None:
     self.env.temp_index = 0
     op = LoadInt(5)
     self.block.ops.append(op)
     self.env.add_op(op)
     fn = FuncIR('myfunc', None, 'mod', FuncSignature([self.arg], list_rprimitive),
                 [self.block], self.env)
     emitter = Emitter(EmitterContext(['mod']))
     generate_native_function(fn, emitter, 'prog.py', 'prog')
     result = emitter.fragments
     assert_string_arrays_equal(
         [
             'static PyObject *CPyDef_myfunc(CPyTagged cpy_r_arg) {\n',
             '    CPyTagged cpy_r_r0;\n',
             'CPyL0: ;\n',
             '    cpy_r_r0 = 10;\n',
             '}\n',
         ],
         result, msg='Generated code invalid')
Пример #7
0
    def generate_c_for_modules(self) -> List[Tuple[str, str]]:
        file_contents = []
        multi_file = self.use_shared_lib and self.multi_file

        base_emitter = Emitter(self.context)
        base_emitter.emit_line('#include "__native.h"')
        emitter = base_emitter

        for (_, literal), identifier in self.literals.items():
            if isinstance(literal, int):
                symbol = emitter.static_name(identifier, None)
                self.declare_global('CPyTagged ', symbol)
            else:
                self.declare_static_pyobject(identifier, emitter)

        for module_name, module in self.modules:
            if multi_file:
                emitter = Emitter(self.context)
                emitter.emit_line('#include "__native.h"')

            self.declare_module(module_name, emitter)
            self.declare_internal_globals(module_name, emitter)
            self.declare_imports(module.imports, emitter)
            # Finals must be last (types can depend on declared above)
            self.define_finals(module.final_names, emitter)

            for cl in module.classes:
                generate_class(cl, module_name, emitter)

            # Generate Python extension module definitions and module initialization functions.
            self.generate_module_def(emitter, module_name, module)

            for fn in module.functions:
                emitter.emit_line()
                generate_native_function(fn, emitter, self.source_paths[module_name], module_name)
                if fn.name != TOP_LEVEL_NAME:
                    emitter.emit_line()
                    generate_wrapper_function(fn, emitter)

            if multi_file:
                name = ('__native_{}.c'.format(emitter.names.private_name(module_name)))
                file_contents.append((name, ''.join(emitter.fragments)))

        sorted_decls = self.toposort_declarations()

        emitter = base_emitter
        self.generate_globals_init(emitter)
        for declaration in sorted_decls:
            if declaration.defn:
                emitter.emit_lines(*declaration.defn)

        emitter.emit_line()

        declarations = Emitter(self.context)
        declarations.emit_line('#include <Python.h>')
        declarations.emit_line('#include <CPy.h>')
        declarations.emit_line()
        declarations.emit_line('int CPyGlobalsInit(void);')
        declarations.emit_line()

        for declaration in sorted_decls:
            if declaration.needs_extern:
                declarations.emit_lines(
                    'extern {}'.format(declaration.decl[0]), *declaration.decl[1:])
                emitter.emit_lines(*declaration.decl)
            else:
                declarations.emit_lines(*declaration.decl)

        for module_name, module in self.modules:
            self.declare_finals(module.final_names, declarations)
            for cl in module.classes:
                generate_class_type_decl(cl, emitter, declarations)
            for fn in module.functions:
                generate_function_declaration(fn, declarations)

        if self.shared_lib_name:
            self.generate_shared_lib_init(emitter)

        return file_contents + [('__native.c', ''.join(emitter.fragments)),
                                ('__native.h', ''.join(declarations.fragments))]
Пример #8
0
    def generate_c_for_modules(self) -> List[Tuple[str, str]]:
        file_contents = []
        multi_file = self.use_shared_lib and self.multi_file

        base_emitter = Emitter(self.context)
        # When not in multi-file mode we just include the runtime
        # library c files to reduce the number of compiler invocations
        # needed
        if not self.multi_file:
            base_emitter.emit_line('#include "CPy.c"')
            base_emitter.emit_line('#include "getargs.c"')
        base_emitter.emit_line('#include "__native{}.h"'.format(
            self.group_suffix))
        base_emitter.emit_line('#include "__native_internal{}.h"'.format(
            self.group_suffix))
        emitter = base_emitter

        for (_, literal), identifier in self.literals.items():
            if isinstance(literal, int):
                symbol = emitter.static_name(identifier, None)
                self.declare_global('CPyTagged ', symbol)
            else:
                self.declare_static_pyobject(identifier, emitter)

        for module_name, module in self.modules:
            if multi_file:
                emitter = Emitter(self.context)
                emitter.emit_line('#include "__native{}.h"'.format(
                    self.group_suffix))
                emitter.emit_line('#include "__native_internal{}.h"'.format(
                    self.group_suffix))

            self.declare_module(module_name, emitter)
            self.declare_internal_globals(module_name, emitter)
            self.declare_imports(module.imports, emitter)

            for cl in module.classes:
                if cl.is_ext_class:
                    generate_class(cl, module_name, emitter)

            # Generate Python extension module definitions and module initialization functions.
            self.generate_module_def(emitter, module_name, module)

            for fn in module.functions:
                emitter.emit_line()
                generate_native_function(fn, emitter,
                                         self.source_paths[module_name],
                                         module_name)
                if fn.name != TOP_LEVEL_NAME:
                    emitter.emit_line()
                    generate_wrapper_function(fn, emitter,
                                              self.source_paths[module_name],
                                              module_name)

            if multi_file:
                name = ('__native_{}.c'.format(
                    emitter.names.private_name(module_name)))
                file_contents.append((name, ''.join(emitter.fragments)))

        # The external header file contains type declarations while
        # the internal contains declarations of functions and objects
        # (which are shared between shared libraries via dynamic
        # exports tables and not accessed directly.)
        ext_declarations = Emitter(self.context)
        ext_declarations.emit_line('#ifndef MYPYC_NATIVE{}_H'.format(
            self.group_suffix))
        ext_declarations.emit_line('#define MYPYC_NATIVE{}_H'.format(
            self.group_suffix))
        ext_declarations.emit_line('#include <Python.h>')
        ext_declarations.emit_line('#include <CPy.h>')

        declarations = Emitter(self.context)
        declarations.emit_line('#ifndef MYPYC_NATIVE_INTERNAL{}_H'.format(
            self.group_suffix))
        declarations.emit_line('#define MYPYC_NATIVE_INTERNAL{}_H'.format(
            self.group_suffix))
        declarations.emit_line('#include <Python.h>')
        declarations.emit_line('#include <CPy.h>')
        declarations.emit_line('#include "__native{}.h"'.format(
            self.group_suffix))
        declarations.emit_line()
        declarations.emit_line('int CPyGlobalsInit(void);')
        declarations.emit_line()

        for module_name, module in self.modules:
            self.declare_finals(module_name, module.final_names, declarations)
            for cl in module.classes:
                generate_class_type_decl(cl, emitter, ext_declarations,
                                         declarations)
            for fn in module.functions:
                generate_function_declaration(fn, declarations)

        for lib in sorted(self.context.group_deps):
            declarations.emit_lines(
                '#include "__native_{}.h"'.format(lib),
                'struct export_table_{} exports_{};'.format(lib, lib))

        sorted_decls = self.toposort_declarations()

        emitter = base_emitter
        self.generate_globals_init(emitter)

        emitter.emit_line()

        for declaration in sorted_decls:
            decls = ext_declarations if declaration.is_type else declarations
            if not declaration.is_type:
                decls.emit_lines('extern {}'.format(declaration.decl[0]),
                                 *declaration.decl[1:])
                # If there is a definition, emit it. Otherwise repeat the declaration
                # (without an extern).
                if declaration.defn:
                    emitter.emit_lines(*declaration.defn)
                else:
                    emitter.emit_lines(*declaration.decl)
            else:
                decls.emit_lines(*declaration.decl)

        if self.group_name:
            self.generate_export_table(ext_declarations, emitter)

            self.generate_shared_lib_init(emitter)

        ext_declarations.emit_line('#endif')
        declarations.emit_line('#endif')

        return file_contents + [
            ('__native{}.c'.format(self.group_suffix), ''.join(
                emitter.fragments)),
            ('__native_internal{}.h'.format(self.group_suffix), ''.join(
                declarations.fragments)),
            ('__native{}.h'.format(self.group_suffix), ''.join(
                ext_declarations.fragments)),
        ]
Пример #9
0
    def generate_c_for_modules(self) -> List[Tuple[str, str]]:
        file_contents = []
        multi_file = self.use_shared_lib and self.multi_file

        base_emitter = Emitter(self.context)
        base_emitter.emit_line('#include "__native.h"')
        emitter = base_emitter

        for (_, literal), identifier in self.literals.items():
            if isinstance(literal, int):
                symbol = emitter.static_name(identifier, None)
                self.declare_global('CPyTagged ', symbol)
            else:
                self.declare_static_pyobject(identifier, emitter)

        for module_name, module in self.modules:
            if multi_file:
                emitter = Emitter(self.context)
                emitter.emit_line('#include "__native.h"')

            self.declare_module(module_name, emitter)
            self.declare_internal_globals(module_name, emitter)
            self.declare_imports(module.imports, emitter)
            # Finals must be last (types can depend on declared above)
            self.define_finals(module.final_names, emitter)

            for cl in module.classes:
                generate_class(cl, module_name, emitter)

            # Generate Python extension module definitions and module initialization functions.
            self.generate_module_def(emitter, module_name, module)

            for fn in module.functions:
                emitter.emit_line()
                generate_native_function(fn, emitter,
                                         self.source_paths[module_name],
                                         module_name)
                if fn.name != TOP_LEVEL_NAME:
                    emitter.emit_line()
                    generate_wrapper_function(fn, emitter)

            if multi_file:
                name = ('__native_{}.c'.format(
                    emitter.names.private_name(module_name)))
                file_contents.append((name, ''.join(emitter.fragments)))

        sorted_decls = self.toposort_declarations()

        emitter = base_emitter
        self.generate_globals_init(emitter)
        for declaration in sorted_decls:
            if declaration.defn:
                emitter.emit_lines(*declaration.defn)

        emitter.emit_line()

        # Generate a dummy initialization function for the shared lib,
        # since the windows linker gets mad if it isn't present.
        if self.shared_lib_name:
            emitter.emit_line()
            emitter.emit_lines(
                'PyMODINIT_FUNC PyInit_lib{}(void)'.format(
                    self.shared_lib_name),
                '{',
                'PyErr_SetString(PyExc_RuntimeError, "mypyc shared lib is not to be imported");',
                'return NULL;',
                '}',
            )

        declarations = Emitter(self.context)
        declarations.emit_line('#include <Python.h>')
        declarations.emit_line('#include <CPy.h>')
        declarations.emit_line()
        declarations.emit_line('int CPyGlobalsInit(void);')
        declarations.emit_line()

        for declaration in sorted_decls:
            declarations.emit_lines(*declaration.decl)

        for module_name, module in self.modules:
            self.declare_finals(module.final_names, declarations)
            for cl in module.classes:
                generate_class_type_decl(cl, declarations)
            for fn in module.functions:
                generate_function_declaration(fn, declarations)

        return file_contents + [('__native.c', ''.join(emitter.fragments)),
                                ('__native.h', ''.join(declarations.fragments))
                                ]
Пример #10
0
    def generate_c_for_modules(self) -> List[Tuple[str, str]]:
        file_contents = []
        multi_file = self.use_shared_lib and self.multi_file

        base_emitter = Emitter(self.context)
        base_emitter.emit_line('#include "__native.h"')
        base_emitter.emit_line('#include "__native_internal.h"')
        emitter = base_emitter

        for (_, literal), identifier in self.literals.items():
            if isinstance(literal, int):
                symbol = emitter.static_name(identifier, None)
                self.declare_global('CPyTagged ', symbol)
            else:
                self.declare_static_pyobject(identifier, emitter)

        for module_name, module in self.modules:
            if multi_file:
                emitter = Emitter(self.context)
                emitter.emit_line('#include "__native.h"')
                emitter.emit_line('#include "__native_internal.h"')

            self.declare_module(module_name, emitter)
            self.declare_internal_globals(module_name, emitter)
            self.declare_imports(module.imports, emitter)
            # Finals must be last (types can depend on declared above)
            self.define_finals(module_name, module.final_names, emitter)

            for cl in module.classes:
                if cl.is_ext_class:
                    generate_class(cl, module_name, emitter)

            # Generate Python extension module definitions and module initialization functions.
            self.generate_module_def(emitter, module_name, module)

            for fn in module.functions:
                emitter.emit_line()
                generate_native_function(fn, emitter, self.source_paths[module_name], module_name)
                if fn.name != TOP_LEVEL_NAME:
                    emitter.emit_line()
                    generate_wrapper_function(
                        fn, emitter, self.source_paths[module_name], module_name)

            if multi_file:
                name = ('__native_{}.c'.format(emitter.names.private_name(module_name)))
                file_contents.append((name, ''.join(emitter.fragments)))

        # The external header file contains type declarations while
        # the internal contains declarations of functions and objects
        # (which are shared between shared libraries via dynamic
        # linking tables and not accessed directly.)
        ext_declarations = Emitter(self.context)
        ext_declarations.emit_line('#ifndef MYPYC_NATIVE_H')
        ext_declarations.emit_line('#define MYPYC_NATIVE_H')
        ext_declarations.emit_line('#include <Python.h>')
        ext_declarations.emit_line('#include <CPy.h>')

        declarations = Emitter(self.context)
        declarations.emit_line('#ifndef MYPYC_NATIVE_INTERNAL_H')
        declarations.emit_line('#define MYPYC_NATIVE_INTERNAL_H')
        declarations.emit_line('#include <Python.h>')
        declarations.emit_line('#include <CPy.h>')
        declarations.emit_line('#include "__native.h"')
        declarations.emit_line()
        declarations.emit_line('int CPyGlobalsInit(void);')
        declarations.emit_line()

        for module_name, module in self.modules:
            self.declare_finals(module_name, module.final_names, declarations)
            for cl in module.classes:
                generate_class_type_decl(cl, emitter, ext_declarations, declarations)
            for fn in module.functions:
                generate_function_declaration(fn, declarations)

        sorted_decls = self.toposort_declarations()

        emitter = base_emitter
        self.generate_globals_init(emitter)
        for declaration in sorted_decls:
            if declaration.defn:
                emitter.emit_lines(*declaration.defn)

        emitter.emit_line()

        for declaration in sorted_decls:
            decls = ext_declarations if declaration.is_type else declarations
            if not declaration.is_type:
                decls.emit_lines(
                    'extern {}'.format(declaration.decl[0]), *declaration.decl[1:])
                emitter.emit_lines(*declaration.decl)
            else:
                decls.emit_lines(*declaration.decl)

        if self.shared_lib_name:
            self.generate_shared_lib_init(emitter)

        ext_declarations.emit_line('#endif')
        declarations.emit_line('#endif')

        return file_contents + [('__native.c', ''.join(emitter.fragments)),
                                ('__native_internal.h', ''.join(declarations.fragments)),
                                ('__native.h', ''.join(ext_declarations.fragments)),
                                ]