示例#1
0
    def _generate_global_constants_wrapper(self, block):
        forward_decl = set()
        memblock = CodeBlock.CodeBlock()
        usable_id = 6329

        for name in sorted(self.global_constants.keys()):
            const = self.global_constants[name]

            if not const.type.is_trivial() and not const.type.cvt:
                borrower = self.namer.borrower(const.type.intrinsic_type())
                forward_decl.add("PyObject *%s(const %s &);" % (
                    borrower, const.type.intrinsic_type()
                ))

                memblock.write_code('PyModule_AddObject(m, "%s", %s(%s%s));' % (
                    self.namer.to_python(const.name), borrower,
                    '*' if const.type.is_ptr() else "",
                    const.name
                ))
            else:  # TODO: Review
                bld = const.type.get_build_value_idecl(const.name, namer=self.namer)
                one_line = '\n' not in bld

                if one_line:
                    arg = bld[(16 + len(const.name)):-1]
                else:
                    py_var_name = "py_var_%d" % usable_id
                    usable_id += 1

                    bld = const.type.get_build_value_idecl(
                        const.name, py_var_name, namer=self.namer
                    )

                    memblock.append_blank_line()
                    memblock.write_code("{")
                    memblock.indent()
                    memblock.write_code(bld)

                    arg = py_var_name

                memblock.write_code('PyModule_AddObject(m, "%s", %s);' % (
                    self.namer.to_python(const.name), arg
                ))

                if not one_line:
                    memblock.unindent()
                    memblock.write_code('}')
                    memblock.append_blank_line()

        if len(forward_decl) > 0:
            block.write_lines(forward_decl)
            block.append_blank_line()

        register = self.namer.globals_register(self._pyside_full_name())
        block.write_code(Code.Snippets.global_constants_register_sig % register)

        with CodeBlock.BracketThis(block):
            block.write_code(memblock.flush())
示例#2
0
    def _generate_bases_register(self):
        self.block.write_code(Code.Snippets.register_bases_sig % (
            self.namer.method_holder(self.full_name),
            self.namer.bases_register(self.full_name),
        ))

        if len(self.direct_bases) == 0:
            self.block.lines[-1] += " {}\n"
            return

        with CodeBlock.BracketThis(self.block):
            my_type = self.namer.pytype(self.full_name)

            self.block.write_code(my_type + ".tp_base = &%s;" %
                                  (self.namer.pytype(self.direct_bases[0]), ))

            if len(self.direct_bases) > 1:
                self.block.append_blank_line()
                self.block.write_code(my_type +
                                      ".tp_bases = PyTuple_New(%d);" %
                                      (len(self.direct_bases)))

                for index, base in enumerate(self.direct_bases):
                    self.block.write_code(
                        Code.Snippets.base_tuple_item % {
                            "BASE_TYPE": self.namer.pytype(base),
                            "INDEX": index,
                            "DERIVED_TYPE": my_type,
                        })
示例#3
0
    def _generate_setter(self, f):
        if not f.type.is_copy_assignable():
            return

        self.block.write_code(
            Code.Snippets.field_setter_sig %
            (self.namer.setter(f.raw_name), self.namer.pyobj(self.full_name)))

        with CodeBlock.BracketThis(self.block):
            self.block.write_code(
                Code.Snippets.TestSubclassAndOffset % {
                    "MY_PYTYPE": self.namer.pytype(self.full_name),
                    "WRAPT": self.get_wrapt_class_name(),
                })

            self.block.append_blank_line()
            self.block.write_code(
                f.type.get_extractor_code(f.name, "py_value", "return -1;",
                                          self.namer))

            self.block.append_blank_line()

            if f.type.is_class_value():
                self.block.write_lines((
                    "PBPP_BEGIN_ALLOW_THREADS",
                    "py_cxx_obj->%s = %s;" % (f.raw_name, f.name),
                    "PBPP_END_ALLOW_THREADS",
                    "",
                ))
            else:
                self.block.write_code("py_cxx_obj->%s = %s;" %
                                      (f.raw_name, f.name))

            self.block.write_code("return 0;")
示例#4
0
    def _generate_enums(self):
        self.block.write_code(Code.Snippets.register_enums_sig %
                              self.namer.enums_register(self.full_name))

        if len(self.enums.values) > 0:
            with CodeBlock.BracketThis(self.block):
                my_type = self.namer.pytype(self.full_name)
                action = Code.Snippets.register_class_enum_values % my_type

                self.enums.generate(self.block, action)
        else:
            self.block.lines[-1] += " {}\n"
示例#5
0
def _write_overloads(block,
                     namer,
                     func_name,
                     signatures,
                     err_return,
                     actions,
                     finish_directly,
                     pyside_debug_name=None):
    assert len(signatures) > 1
    assert len(signatures) == len(actions)

    func_name = func_name.upper()
    label_ok = "PBPP__%s_OK" % func_name

    block.write_code(Code.Snippets.overloading_exception_cache %
                     len(signatures))

    for index, (sig, action) in enumerate(zip(signatures, actions)):
        if index > 0:
            block.write_code((Code.Snippets.overloading_label + ':') % {
                "FUNC_NAME": func_name,
                "INDEX": index,
            },
                             temp_indent=0)

        if index < len(signatures) - 1:
            err_handler = "goto " + Code.Snippets.overloading_label % {
                "FUNC_NAME": func_name,
                "INDEX": index + 1,
            } + ';'
        else:
            err_handler = (Code.Snippets.overloading_restore_exceptions %
                           len(signatures)) + err_return

        with CodeBlock.BracketThis(block, preamble=""):
            r = Code.Snippets.overloading_cache_exception + err_handler
            sig.write_args_parsing_code(block, namer, True, r,
                                        pyside_debug_name)

            block.write_code(action % sig.get_parameters_string())
            if not finish_directly:
                block.write_code("goto %s;" % label_ok)

    if not finish_directly:
        block.write_code(label_ok + ':', temp_indent=0)
    else:
        block.lines.pop()  # Remove the last empty line
示例#6
0
    def _generate_getter(self, f):
        self.block.write_code(
            Code.Snippets.field_getter_sig %
            (self.namer.getter(f.raw_name), self.namer.pyobj(self.full_name)))

        with CodeBlock.BracketThis(self.block):
            self.block.write_code(
                Code.Snippets.TestSubclassAndOffset % {
                    "MY_PYTYPE": self.namer.pytype(self.full_name),
                    "WRAPT": self.get_wrapt_class_name(),
                })

            self.block.append_blank_line()

            tmp_type = f.type
            if f.type.is_class_value():
                tmp_type = f.type.class_value_to_ref(const=True)

            self.block.write_code(
                tmp_type.get_build_value_idecl("py_cxx_obj->" + f.raw_name,
                                               namer=self.namer))

            self.block.append_blank_line()
            self.block.write_code("return py_%s;" % f.raw_name)
示例#7
0
    def write_args_parsing_code(self, block, namer, enable_kw, err_return,
                                pyside_debug_name):
        error_handler_label = "PBPP__ARGS_PARSING_ERROR_HANDLER_" + str(
            block.size())
        require_error_handler_label = False

        to_cxx = []
        count0 = 0

        for arg in self.args:
            if arg.type.cvt:
                block.write_code(
                    arg.type.cvt.args_parsing_declare_vars(
                        arg.type, arg.name, arg.defv))

                goto_error_return = "goto %s;" % error_handler_label
                if arg.type.cvt.args_parsing_require_error_handling(arg.type):
                    require_error_handler_label = True

                extracting_code = arg.type.cvt.args_parsing_extracting_code(
                    arg.type, arg.name, arg.defv, goto_error_return, namer)

                if len(extracting_code) > 0:
                    to_cxx += extracting_code.split('\n')

                Session.header_jar().add_headers(
                    arg.type.cvt.additional_headers(arg.type))
            elif arg.type.is_built_in():
                if arg.type.is_bool():
                    block.write_code("PyObject *py__%s = nullptr;" % arg.name)

                    if arg.defv is None:
                        extracting_code = Types.extract_as_bool("py__%s" %
                                                                arg.name)
                        to_cxx.append(
                            arg.type.declare_var(arg.name, extracting_code))
                    else:
                        to_cxx.append(arg.type.declare_var(arg.name, arg.defv))

                        extracting_code = (
                            Code.Snippets.check_and_extract_as_bool % {
                                "VAR_NAME": arg.name
                            }).split('\n')

                        to_cxx += extracting_code
                else:
                    block.write_code(arg.type.declare_var(arg.name, arg.defv))
            elif arg.type.is_ref():
                if not arg.type.is_trivial():
                    pytype = namer.pytype(arg.type.intrinsic_type())
                    block.write_code("extern PyTypeObject %s;" % pytype)

                block.write_code("PyObject *py__%s = nullptr;" % arg.name)
                cpp_ptr_type = arg.type.ref_to_ptr()

                if arg.type.is_trivial():
                    capsule_ensure_reference = (
                        Code.Snippets.capsule_ensure_reference % {
                            "VAR_NAME": arg.name,
                            "CAP_NAME": arg.type.decl_no_const(),
                            "ERROR_RETURN": "goto %s;" % error_handler_label,
                        }).split('\n')

                    require_error_handler_label = True

                    if arg.defv is None:
                        to_cxx += capsule_ensure_reference

                        init_expr = '*((%s) PyCapsule_GetPointer(py__%s, "%s"))' % (
                            (
                                cpp_ptr_type.decl(),
                                arg.name,
                                arg.type.decl_no_const(),
                            ))

                        to_cxx.append(arg.type.declare_var(
                            arg.name, init_expr))
                    else:
                        var_ptr = "py_cxx_%s_ptr" % arg.name
                        init_expr = "pbpp::Types::ToPointer(%s)" % arg.defv
                        to_cxx.append(
                            cpp_ptr_type.declare_var(var_ptr, init_expr))

                        to_cxx.append("if (py__%s) {" % arg.name)
                        to_cxx.append(">>>")
                        to_cxx += capsule_ensure_reference
                        to_cxx.append(
                            var_ptr +
                            ' = (%s) PyCapsule_GetPointer(py__%s, "%s");' % (
                                cpp_ptr_type,
                                arg.name,
                                arg.type.decl_no_const(),
                            ))
                        to_cxx.append("<<<")
                        to_cxx.append("}")

                        to_cxx.append(
                            arg.type.declare_var(arg.name, '*' + var_ptr))
                else:  # reference to class
                    if arg.defv is None:
                        init_expr = '*' + Code.Snippets.external_type_real_ptr % {
                            "CLASS": arg.type.intrinsic_type(),
                            "PYOBJ_PTR": "py__" + arg.name
                        }

                        to_cxx.append(arg.type.declare_var(
                            arg.name, init_expr))
                    else:
                        defv_rv = "py_cxx_%s_defv_rv" % arg.name
                        var_ptr = "py_cxx_%s_ref2ptr" % arg.name

                        to_cxx.append("auto &&%s = %s;" % (defv_rv, arg.defv))
                        to_cxx.append(
                            cpp_ptr_type.declare_var(var_ptr, '&' + defv_rv))

                        to_cxx.append("if (py__%s) {" % arg.name)
                        to_cxx.append(">>>")
                        to_cxx.append(
                            var_ptr + ' = ' +
                            Code.Snippets.external_type_real_ptr % {
                                "CLASS": arg.type.intrinsic_type(),
                                "PYOBJ_PTR": "py__" + arg.name
                            } + ';')
                        to_cxx.append("<<<")
                        to_cxx.append("}")

                        to_cxx.append(
                            arg.type.declare_var(arg.name, '*' + var_ptr))
            elif arg.type.decl_no_const() == "PyObject *":
                init_expr = "nullptr"
                if arg.defv is not None:
                    init_expr = arg.defv

                block.write_code(arg.type.declare_var(arg.name, init_expr))
            else:  # pointer or argument pass by value
                if arg.type.is_trivial():  # trivial pointer
                    pytype = "PyCapsule_Type"

                    block.write_code("PyObject *py__%s = nullptr;" % arg.name)
                    extracting_code = '(%s) PyCapsule_GetPointer(py__%s, "%s")' % (
                        (
                            arg.type.decl(),
                            arg.name,
                            arg.type.decl_no_const(),
                        ))

                    to_cxx.append(
                        arg.type.declare_var(
                            arg.name, arg.defv if arg.defv else "nullptr"))
                else:
                    pytype = namer.pytype(arg.type.intrinsic_type())

                    block.write_code("extern PyTypeObject %s;" % pytype)
                    block.write_code("PyObject *py__%s = nullptr;" % arg.name)

                    extracting_code = Code.Snippets.external_type_real_ptr % {
                        "CLASS": arg.type.intrinsic_type(),
                        "PYOBJ_PTR": "py__" + arg.name
                    }

                    if not arg.type.is_ptr():  # args pass by value
                        extracting_code = '*' + extracting_code

                        if not arg.defv:
                            init_expr = extracting_code
                            extracting_code = None  # DONE processing
                        else:
                            init_expr = arg.defv

                        to_cxx.append(arg.type.declare_var(
                            arg.name, init_expr))
                    else:
                        to_cxx.append(arg.type.declare_var(
                            arg.name, "nullptr"))

                if arg.type.is_ptr() or arg.defv is not None:
                    memblock = CodeBlock.CodeBlock()

                    if arg.defv is not None:
                        memblock.write_code("if (py__%s) {" % arg.name)
                        memblock.indent()

                    if arg.type.is_ptr():
                        memblock.write_code("if (py__%s != Py_None) {" %
                                            arg.name)
                        memblock.indent()

                        memblock.write_code(
                            Code.Snippets.extract_pointer % {
                                "VAR_NAME": arg.name,
                                "PYTYPE": pytype,
                                "POINTER_TYPE": arg.type.intrinsic_type(),
                                "EXTRACTING_CODE": extracting_code,
                                "ERROR_HANDLER":
                                "goto %s;" % error_handler_label,
                            })

                        require_error_handler_label = True

                        memblock.unindent()
                        memblock.write_code("}")
                    else:
                        memblock.write_code("%s = %s;" %
                                            (arg.name, extracting_code))

                    if arg.defv is not None:
                        memblock.unindent()
                        memblock.write_code('}')

                    to_cxx += memblock.lines

            if count0 < len(to_cxx):
                to_cxx.append("")
                count0 = len(to_cxx)

        if enable_kw:
            kws = "nullptr"
            if not self.empty():
                kws = ", ".join(['"%s"' % kw
                                 for kw in self.get_keywords()] + ["nullptr"])

            block.write_code("const char *py_keywords[] = { %s };" % kws)
            block.append_blank_line()

        parser_idecl = self.build_parser_idecl(namer=namer,
                                               enable_kw=enable_kw,
                                               func_name=pyside_debug_name)

        block.write_error_check("!" + parser_idecl,
                                handler=err_return,
                                handler_label=error_handler_label
                                if require_error_handler_label else None)

        block.append_blank_line()
        if len(to_cxx) > 0:
            block.write_lines(to_cxx)
示例#8
0
    def args_parsing_extracting_code(self, cpp_type, arg_name, defv,
                                     error_return, namer):
        reference_type = self.reference_type(cpp_type)
        should_write_back = reference_type in (
            "REF",
            "PTR",
        )
        py_var_name = "py__" + arg_name

        block = CodeBlock.CodeBlock()

        if cpp_type.is_ptr():
            conditions = []
            if defv is not None:
                conditions.append(py_var_name)

            conditions.append(py_var_name + " != Py_None")
            conditions.append(self.negative_checker(cpp_type, py_var_name))

            block.write_error_check(" && ".join(conditions), error_return)

        container_type = Types.Type((cpp_type.intrinsic_type(), ), 0, "Class")
        pyobject_type = Types.Type((
            "PyObject",
            "*",
        ), 0, "PointerType")

        key_extractor = self.K.get_extractor_code("key", "py_key",
                                                  "return false;", namer)
        key_extractor = Types.declaring_to_assigning(self.K, "key",
                                                     key_extractor)
        key_extractor += "\nreturn true;"

        if should_write_back:
            key_builder = self.K.get_build_value_idecl("key", "py_key", namer)
            key_builder = Types.declaring_to_assigning(pyobject_type, "py_key",
                                                       key_builder)
            key_builder += "\nreturn true;"
        else:
            key_builder = "return false;"

        val_extractor = self.V.get_extractor_code("val", "py_val",
                                                  "return false;", namer)
        val_extractor = Types.declaring_to_assigning(self.V, "val",
                                                     val_extractor)
        val_extractor += "\nreturn true;"

        if should_write_back:
            val_builder = self.V.get_build_value_idecl("val", "py_val", namer)
            val_builder = Types.declaring_to_assigning(pyobject_type, "py_val",
                                                       val_builder)
            val_builder += "\nreturn true;"
        else:
            val_builder = "return false;"

        if defv is not None:
            set_defv = "%s.SetDefault(%s);\n" % (arg_name, defv)
        else:
            set_defv = ""

        block.write_code(
            Code.Snippets.extract_dict % {
                "CONTAINER_TYPE": container_type.decl(),
                "KEY_TYPE": self.K.decl(),
                "K_SPACE": "" if self.K.is_ptr() else " ",
                "VALUE_TYPE": self.V.decl(),
                "V_SPACE": "" if self.V.is_ptr() else " ",
                "VAR_NAME": arg_name,
                "PY_VAR_NAME": py_var_name,
                "REFERENCE_TYPE": reference_type,
                "KEY_BUILDER": key_builder,
                "KEY_EXTRACTOR": key_extractor,
                "VALUE_BUILDER": val_builder,
                "VALUE_EXTRACTOR": val_extractor,
                "SET_DEFAULT_VALUE": set_defv,
                "ERROR_RETURN": error_return,
            })

        return block.flush()
示例#9
0
    def generate_methods(self, block, namer, scope_obj):
        cls = scope_obj if isinstance(scope_obj, Class.Class) else None

        for mname in sorted(self.methods.keys()):
            overloads = sorted(self.methods[mname],
                               lambda x, y: cmp(x.raw_sig, y.raw_sig))

            if not _validate_overloads(overloads):
                ns = cls.full_name + "::" if cls else ""
                raise RuntimeError("`%s%s`: _validate_overloads() failed." %
                                   (ns, mname))

            signatures = []
            actions = []

            for m in overloads:
                is_real_class_member = cls and not m.free_function

                if cls and m.free_function:
                    args_tk = copy.copy(m.args)
                    args_tk.__class__ = _InjectedMethod_TupleAndKeywords
                    args_tk.args = args_tk.args[1:]

                    signatures.append(args_tk)
                else:
                    signatures.append(m.args)

                if is_real_class_member:
                    invoker = "py_cxx_obj->"
                    if m.static:
                        invoker = cls.get_wrapt_class_name() + "::"
                else:
                    invoker = "" if not m.namespace else m.namespace + "::"

                if m.returns.decl() != "void":
                    if m.returns.category() == Types.CLASS:
                        fmt = "%s(%s%s(%%s));\n%s\n\n"
                    else:
                        fmt = "%s = %s%s(%%s);\n%s\n\n"

                    action = "PBPP_BEGIN_ALLOW_THREADS\n"
                    action += fmt % (
                        m.returns.join_type_and_name("py_cxx_retval"),
                        invoker,
                        m.name,  # ATTENTION!
                        "PBPP_END_ALLOW_THREADS")

                    if m.returns.is_ptr():
                        action += Code.Snippets.ensure_not_null + '\n'

                    if m.returns.is_pyobject_ptr():
                        action += "return py_cxx_retval;"
                    else:
                        idecl = m.returns.get_build_value_idecl(
                            var_name="py_cxx_retval",
                            py_var_name="py_retval",
                            namer=namer)

                        action += idecl + "\nreturn (PyObject *) py_retval;"
                else:
                    action = Code.Snippets.invoke_fx_returning_void % (invoker,
                                                                       m.name)

                actions.append(action)

            if len(overloads) == 1 and overloads[0].args.empty():
                if cls:
                    method_sig = Code.Snippets.method_sig_no_arg
                else:
                    method_sig = Code.Snippets.ff_sig_no_arg
            else:
                if cls:
                    method_sig = Code.Snippets.method_sig
                else:
                    method_sig = Code.Snippets.ff_sig

            block.write_code(
                method_sig % {
                    "PYOBJ_NAME":
                    "" if not cls else namer.pyobj(cls.full_name),
                    "NAME": self._normalize_method_name(mname, namer, cls),
                })

            with CodeBlock.BracketThis(block):
                if cls:
                    pyside = cls.full_name + "::" + mname
                else:
                    pyside = mname

                if not cls or (hasattr(overloads[0], "static")
                               and overloads[0].static):
                    pass
                else:
                    block.write_code(
                        Code.Snippets.TestSubclassAndOffset % {
                            "CLS_NAME": cls.full_name,
                            "MY_PYTYPE": namer.pytype(cls.full_name),
                            "WRAPT": cls.get_wrapt_class_name(),
                        })

                    block.append_blank_line()

                if len(overloads) == 1:
                    if not signatures[0].empty():
                        signatures[0].write_args_parsing_code(
                            block, namer, True, "return nullptr;", pyside)

                    block.write_code(actions[0] %
                                     signatures[0].get_parameters_string())
                else:
                    _write_overloads(block=block,
                                     namer=namer,
                                     func_name=mname,
                                     signatures=signatures,
                                     err_return="return nullptr;",
                                     actions=actions,
                                     finish_directly=True,
                                     pyside_debug_name=pyside)
示例#10
0
    def generate(self, outdir, ext):
        for submodule in self.submodules.values():
            submodule.generate(outdir, ext)

        full_name = self._pyside_full_name()
        output_path = "%s%s%s.py%s" % (
            outdir, os.path.sep, full_name, ext
        )

        if self.is_root():
            self._copy_helpers(outdir)

        if not self.modified and os.path.exists(output_path):
            return

        # Exit this function with care:
        #   Remember to call Session.end()
        Session.begin(self.header_jar)

        fp_mem_block = CodeBlock.CodeBlock()
        fptrs = Fptr.FptrManager()
        self.free_functions.collect_function_pointer_defs(fptrs)
        if not fptrs.empty():
            fptrs.generate(fp_mem_block)
            fp_mem_block.append_blank_line()
            fp_mem_block.append_blank_line()

        ff_mem_block = CodeBlock.CodeBlock()
        ff_table_mem_block = CodeBlock.CodeBlock()
        self.free_functions.generate_methods(ff_mem_block, self.namer, self)
        self.free_functions.generate_methods_table(ff_table_mem_block, self.namer, self)

        template_args = {
            "MNAME": self.name,
            "MNAME_FULL": full_name,
            "MOD_REGISTER": self.get_register_name(),
            "HEADERS": self.header_jar.concat_sorted(),
            "FPTRS": fp_mem_block.flush(),
            "FREE_FUNCTIONS": ff_mem_block.flush(),
            "METHODS_TABLE": ff_table_mem_block.flush(),
        }

        block = CodeBlock.CodeBlock()
        block.write_code(self.header_provider.pch())

        with open(os.path.dirname(__file__) + "/Code/Header.inl") as f:
            block.write_code(f.read() % template_args)

        self._generate_global_constants_wrapper(block)
        self._generate_enums_register(block)

        module_ptr = self.namer.mod_ptr_name(full_name)

        block.write_code(Code.Snippets.define_module_ptr.format(module_ptr))
        block.write_code(Code.Snippets.module_register_header % template_args)
        block.indent()

        block.write_code(self.namer.globals_register(full_name) + "(m);")
        block.write_code(self.namer.enums_register(full_name) + "(m);")
        block.append_blank_line()

        for submodule in self.submodules.values():
            register = submodule.get_register_name()
            block.write_code("PyObject *%s(PyObject *parent);" % register)

        if len(self.submodules) > 0:
            block.append_blank_line()

        for submodule in self.submodules.values():
            block.write_code(submodule.get_register_name() + "(m);")

        if len(self.submodules) > 0:
            block.append_blank_line()

        for cls in self.classes.values():
            cls.mod = 'm' if self.is_root() else module_ptr

        if self.is_root():
            self._register_classes(block, outdir, ext)

        block.write_code(module_ptr + " = m;")
        block.write_code("return m;")
        block.unindent()
        block.write_code("}")

        if self.is_root():
            with open(os.path.dirname(__file__) + "/Code/RootMod.inl") as f:
                block.write_code(f.read() % self.name)


        ns = self._get_cxx_namespace() or self.name
        content = self.blacklist.hook_write(ns, block.flush())

        Util.smart_write(output_path, content)

        self.modified = False

        Session.end()
示例#11
0
    def _generate_enums_register(self, block):
        block.write_code(Code.Snippets.module_enums_register_sig %
                         self.namer.enums_register(self._pyside_full_name()))

        with CodeBlock.BracketThis(block):
            self.enums.generate(block, Code.Snippets.register_module_enum_values)
示例#12
0
    def _generate_wrapper_class(self):
        assert self._require_wrapper_class()

        wrapper_name = self.namer.wrapper_class(self.full_name)
        self.block.write_code("class %s : public %s" %
                              (wrapper_name, self.full_name))

        with CodeBlock.BracketThis(self.block, postscript=';'):
            self.block.write_code("public:", temp_indent=0)
            self.block.write_code(
                self.namer.pyobj(self.full_name) + " *self = nullptr;")
            self.block.append_blank_line()

            if len(self.protected_nonvirtual_members) > 0:
                for m in sorted(self.protected_nonvirtual_members):
                    self.block.write_code(m)

                self.block.append_blank_line()

            for ctor in self.ctors:
                self.block.write_code(
                    wrapper_name + "(%s)" %
                    (ctor.build_function_signature_parameter_list()))

                self.block.indent()
                self.block.write_code(
                    ": %s(%s)" %
                    (self.full_name, ctor.get_parameters_string()))

                self.block.unindent()

                self.block.write_code("{}")
                self.block.append_blank_line()

            if self._get_lifetime_policy() == LT_CXX:
                self.block.write_code(Code.Snippets.wrapper_dtor %
                                      wrapper_name)

            if len(self.virtual_members) == 0:
                self.block.lines = self.block.lines[:
                                                    -1]  # Remove the trailing empty line
                return

            for m in sorted(self.virtual_members,
                            lambda x, y: cmp(x.raw_sig, y.raw_sig)):
                pyside_debug_name = "%s %s" % (m.returns.decl(), m.raw_sig)

                if m.returns.decl()[-1] not in "&*":
                    fmt = "virtual %s %s(%s)%s"
                else:
                    fmt = "virtual %s%s(%s)%s"

                self.block.write_code(fmt % (
                    m.returns.decl(),
                    m.name,
                    m.args.build_function_signature_parameter_list(),
                    " const" if m.raw_sig.endswith(" const") else "",
                ))

                memblock = CodeBlock.CodeBlock()
                names = []

                if m.args.size() > 0:
                    for arg in m.args.args:
                        pyname = "py__" + arg.name
                        names.append("(PyObject *) " + pyname)

                        memblock.write_code(
                            arg.type.get_build_value_idecl(arg.name,
                                                           pyname,
                                                           self.namer,
                                                           raii=True))

                    memblock.append_blank_line()

                names.append("nullptr")

                with CodeBlock.BracketThis(self.block):
                    template_args = {
                        "WRAPT": self.full_name,
                        "SIG": m.raw_sig,
                        "MNAME": m.name,
                        "ARGS_COUNT": m.args.size(),
                        "ARGS": m.args.get_parameters_string(),
                        "BUILD_ARGS": memblock.flush(),
                        "CM_ARGS": ", ".join(names),
                        "RET": m.returns.decl(),
                        "EXCEPTION": "pbpp::CallPyMethodError",
                    }

                    h = Code.Snippets.virtual_method_wrapper_header(
                        m.pure_virtual)
                    self.block.write_code(h % template_args)

                    if m.returns.decl() == "void":
                        self.block.write_code(
                            Code.Snippets.handle_return_void %
                            pyside_debug_name)
                    else:
                        err_handler = "PyErr_Print();\n"
                        err_handler += Code.Snippets.throw_cxxexception % template_args

                        self.block.write_code(
                            m.returns.get_extractor_code(
                                "py_cxx_vm_retval", "py_vm_retval",
                                err_handler, self.namer))

                        self.block.append_blank_line()
                        self.block.write_code("return py_cxx_vm_retval;")

            del self.block.lines[-1]  # Remove the last blank line
示例#13
0
    def _generate_constructors(self):
        name = self.namer.constructor(self.full_name)

        self.block.write_code(Code.Snippets.ctor_sig % {
            "PYOBJ_NAME": self.namer.pyobj(self.full_name),
            "CTOR_NAME": name,
        })

        with CodeBlock.BracketThis(self.block):
            if self.no_accessible_canonical_ctors:
                fmt = Code.Snippets.ctor_error_accessibility
                self.block.write_code(fmt % self.full_name)

                return

            if self._is_abstract():
                self.block.write_code(
                    Code.Snippets.ctor_chk_abstract % {
                        "PYTYPE_NAME": self.namer.pytype(self.full_name),
                        "CLS_NAME": self.full_name,
                    })

            pyside_debug_name = "%s::%s" % (
                self.full_name,
                self.name,
            )
            action = Code.Snippets.constructing % (
                (self.get_wrapt_class_name(), ) * 2)

            if len(self.ctors) == 1:
                args = self.ctors[0]

                self._write_args_parsing_code(args, "return -1;",
                                              pyside_debug_name)
                self.block.write_code(action % args.get_parameters_string())
            else:
                self._write_overloads(name,
                                      self.ctors,
                                      err_return="return -1;",
                                      actions=(action, ) * len(self.ctors),
                                      finish_directly=False,
                                      pyside_debug_name=pyside_debug_name)

            interfaces = Types.PythonAwareClassRegistry.find(self.full_name)
            if interfaces:
                self_setter = "py_self->cxx_obj->" + interfaces.self_setter
                self.block.write_code((self_setter % "(PyObject *) py_self") +
                                      ';')

            if self._require_wrapper_class():
                self.block.write_code("py_self->cxx_obj->self = py_self;")

            self.block.write_code(Code.Snippets.ctor_actions_more %
                                  (self.namer.base_ptr_fixer(self.full_name),
                                   self.flags_assigner.assign(self.full_name)))

            if self._get_lifetime_policy() == LT_CXX:
                self.block.write_code(Code.Snippets.ctor_incref)

            self.block.append_blank_line()
            self.block.write_code("return 0;")
示例#14
0
    def __init__(self, root, node, module, dummy_def=None):
        assert node is not None or dummy_def is not None

        # Only effective while processing
        self.root = root
        self.node = node

        self.namer = module.namer
        self.header_provider = module.header_provider
        self.flags_assigner = module.flags_assigner
        self.blacklist = module.blacklist

        self.all_bases = None
        self.master_bases = None

        self.has_public_copy_ctor = True
        self.final = False

        # No accessible canonical ctors -> disallow subclassing
        # `canonical ctor` refers to a ctor that is not a copy ctor
        self.no_accessible_canonical_ctors = False

        # If true, requires a wrapper class
        # We only save constructors' params, so we can't determine
        # whether the class has any protected constructor when
        # generating the output
        self.has_protected_ctor = False

        # Instantiatable (new-able) != delete-able
        self.dtor_access_type = Access.PUBLIC

        self.protected_nonvirtual_members = set()
        self.public_nonvirtual_methods = []
        self.virtual_members = []
        self.base_vm_collected = False

        self.enums = Enum.Enum()

        self.ctors = []
        self.methods = MethodJar.MethodJar()
        self.fields = []
        self.fptrs = Fptr.FptrManager()

        self.header_jar = HeaderJar.HeaderJar()
        self.header_jar.add_headers((
            "_Python.hxx",
            "_Common.hxx",
        ))
        if module.header_decl:
            self.header_jar.add_headers((module.header_decl, ))

        # These properties only accessed by the Module class
        self.modified = True
        self.m = None

        # For temporary use only, avoid passing it everywhere
        self.block = CodeBlock.CodeBlock()

        if dummy_def is not None:
            self.name = dummy_def.name
            self.full_name = dummy_def.full_name

            self.enum_class = dummy_def.enum_class

            self.nester = dummy_def.nester
            self.direct_bases = []

            # TODO: namespace alias
            if (not dummy_def.namespace and not dummy_def.nester
                    and not dummy_def.enum_class):
                assert self.name == self.full_name

                self.header_jar.add_global(
                    "%s %s;" %
                    ("struct" if dummy_def.is_struct else "class", self.name))

            # Instantiating, destroying, copying or inheriting
            # a dummy class (object) is not allowed

            self.has_public_copy_ctor = False
            self.final = True

            self.no_accessible_canonical_ctors = True
            self.dtor_access_type = Access.PRIVATE
        else:
            Session.begin(self.header_jar)

            self.name = node.attrib["name"]
            self.full_name = node.attrib["demangled"]

            self.enum_class = False

            self.nester = self._get_nester_class()
            self.direct_bases = self._collect_direct_bases()

            self.final = node.attrib.get("final") == "1"

            self._constructors()
            self._destructor()  # Check dtor's access type

            self._methods()
            self._enums(module)
            self._fields()

            Session.end()
示例#15
0
def _test():
    import CodeBlock
    import Converters
    import HeaderJar

    header_jar = HeaderJar.HeaderJar()
    Session.begin(header_jar)

    Converters.add(Converters.WcsConv())

    tk = TupleAndKeywords()
    tk.add_parameter(
        Argument.Argument(Types.Type((
            "int",
            "*",
        ), 1, "FundamentalType"), "foo"))
    tk.add_parameter(
        Argument.Argument(Types.Type((
            "double",
            "&",
        ), 2, "FundamentalType"), "bar"))
    tk.add_parameter(
        Argument.Argument(
            Types.Type((
                "long unsigned int",
                "&",
                "const",
            ), 3, "FundamentalType"), "xyz"))
    tk.add_parameter(
        Argument.Argument(Types.Type((
            "X",
            "const",
            "&",
        ), 4, "Class"), "x"))
    tk.add_parameter(
        Argument.Argument(Types.Type((
            "Y",
            "*",
        ), 5, "Class"), "y"))
    tk.add_parameter(Argument.Argument(Types.Type(("Z", ), 6, "Class"), "z"))
    tk.add_parameter(
        Argument.Argument(Types.Type(("bool", ), 7, "FundamentalType"), "b"))
    tk.add_parameter(
        Argument.Argument(
            Types.Type((
                "wchar_t",
                "const",
                "*",
            ), 8, "PointerType"), "str"))

    print(tk.get_fmt_specifier())
    print(tk.get_keywords())
    print(tk.build_function_signature_parameter_list())

    from Module import PythonNamer
    namer = PythonNamer()

    print(tk.build_parser_idecl(namer=namer))
    _print_empty_line()

    block = CodeBlock.CodeBlock()
    tk.write_args_parsing_code(block, namer, True, "return nullptr;", "<TEST>")

    print(block.flush())
    _print_empty_line()
    _print_empty_line()

    tk = TupleAndKeywords()
    tk.add_parameter(
        Argument.Argument(Types.Type((
            "int",
            "*",
        ), 1, "FundamentalType"), "foo", "nullptr"))
    tk.add_parameter(
        Argument.Argument(Types.Type((
            "double",
            "&",
        ), 2, "FundamentalType"), "bar", "PI"))
    tk.add_parameter(
        Argument.Argument(
            Types.Type((
                "long unsigned int",
                "&",
                "const",
            ), 3, "FundamentalType"), "xyz", "MAXINT"))
    tk.add_parameter(
        Argument.Argument(Types.Type((
            "X",
            "const",
            "&",
        ), 4, "Class"), "x", "_x"))
    tk.add_parameter(
        Argument.Argument(Types.Type((
            "Y",
            "*",
        ), 5, "Class"), "y", "_py"))
    tk.add_parameter(
        Argument.Argument(Types.Type(("Z", ), 6, "Class"), "z", "Z(1990)"))
    tk.add_parameter(
        Argument.Argument(Types.Type(("bool", ), 7, "FundamentalType"), "b",
                          "true"))
    tk.add_parameter(
        Argument.Argument(
            Types.Type((
                "wchar_t",
                "const",
                "*",
            ), 8, "PointerType"), "str", 'L"Hello world!"'))
    tk.write_args_parsing_code(block, namer, True, "return nullptr;", "<TEST>")

    print(block.flush())

    integer = Types.Type(("int", ), 99, "FundamentalType")
    Converters.add(Converters.ListConv(integer))

    tk = TupleAndKeywords()
    tk.add_parameter(
        Argument.Argument(
            Types.Type((
                "std::vector<int>",
                "const",
                "&",
            ), 0, "Class"), "vi", "_vi"))
    tk.write_args_parsing_code(block, namer, True, "return nullptr;", "<TEST>")

    print(block.flush())

    K = Types.Type((
        "wchar_t",
        "const",
        "*",
    ), 111, "PointerType")
    V = Types.Type((
        "wxColour",
        "*",
    ), 112, "PointerType")
    Converters.add(Converters.DictConv(K, V))

    tk = TupleAndKeywords()
    tk.add_parameter(
        Argument.Argument(
            Types.Type((
                "std::map<wchar_t const *, wxColour *>",
                "&",
            ), 0, "Class"), "m"))
    tk.write_args_parsing_code(block, namer, True, "return nullptr;", "<TEST>")

    print(block.flush())
示例#16
0
    def get_extractor_code(self, var_name, py_var_name, error_return, namer=None):
        block = CodeBlock.CodeBlock()

        if self.is_ptr():
            block.write_code(self.declare_var(var_name, "nullptr"))
            block.write_code("if (%s != Py_None) {" % py_var_name)
            block.indent()

        if self.cvt is not None:
            Session.header_jar().add_headers(self.cvt.additional_headers(self))

            negative_checker = self.cvt.negative_checker(self, "(PyObject *) " + py_var_name)
            extracting_code = self.cvt.extracting_code(self, var_name, py_var_name, error_return, namer)
        elif self.is_built_in():
            if self.is_enum():
                dummy_type = "int"
            else:
                dummy_type = self.decl_no_const()

            negative_checker = "!%s((PyObject *) %s)" % (_built_in[dummy_type]["checker"], py_var_name)

            if self.is_bool():
                extracting_code = self.declare_var(var_name, extract_as_bool(py_var_name))
            else:
                extracting_code = Code.Snippets.extract_builtin_type % {
                    "CAST_ENUM": "(%s) " % self.decl() if self.is_enum() else "",
                    "EXTRACTOR": _built_in[dummy_type]["extractor"],
                    "VAR_TYPE": self.decl(),
                    "PY_VAR_NAME": py_var_name,
                    "VAR_NAME": var_name,
                }
        elif self.is_trivial():
            negative_checker = '!PyCapsule_IsValid(%s, "%s")' % (
                py_var_name, self.decl_no_const(),
            )

            extracting_code = '%s = (%s) PyCapsule_GetPointer(%s, "%s");' % (
                var_name, self.decl(), py_var_name, self.decl_no_const(),
            )
        else:
            pytype = namer.pytype(self.intrinsic_type())
            block.write_code("extern PyTypeObject %s;" % pytype)

            negative_checker = "!PyObject_TypeCheck(%s, &%s)" % (py_var_name, pytype)

            if not self.is_ptr():
                extracting_code = self.declare_var(var_name,
                    '*' + Code.Snippets.external_type_real_ptr % {
                        "CLASS": self.intrinsic_type(),
                        "PYOBJ_PTR": py_var_name,
                    })
            else:
                extracting_code = (var_name + " = " +
                   Code.Snippets.external_type_real_ptr % {
                        "CLASS": self.intrinsic_type(),
                        "PYOBJ_PTR": py_var_name,
                    } + ';')

        block.write_code(Code.Snippets.single_var_extractor % {
            "NEGATIVE_CHECKER": negative_checker,
            "VAR_TYPE": self.decl(),
            "PY_VAR_NAME": py_var_name,
            "VAR_NAME": var_name,
            "ERROR_RETURN": error_return,
            "EXTRACTING_CODE": extracting_code,
        })

        if self.is_ptr():
            block.unindent()
            block.write_code('}')

        return block.flush()
示例#17
0
    def generate(self):
        Session.begin(self.header_jar)

        if self._require_wrapper_class():
            self.block.write_code("class %s;" % self.get_wrapt_class_name())
            self.block.append_blank_line()

        self.block.write_code(
            Code.Snippets.pyobj_decl % {
                "WRAPT": self.get_wrapt_class_name(),
                "PYTYPE_NAME": self.namer.pytype(self.full_name),
                "PYOBJ_NAME": self.namer.pyobj(self.full_name),
                "BASE_PTR_FIXER": self.namer.base_ptr_fixer(self.full_name),
            })

        if not self.fptrs.empty():
            self.fptrs.generate(self.block)
            self.block.append_blank_line()

        if self._require_wrapper_class():
            self._generate_wrapper_class()

        if not self.enum_class:
            self._generate_borrower()

        if self.copy_ready():
            self._generate_copyer()

        # Use a dummy subclass as method holder to invoke protected members
        method_holder = self.namer.method_holder(self.full_name)

        if self.allows_subclassing() or self.enum_class:
            if not self.enum_class:
                method_wrapper_base = self.full_name
            else:
                method_wrapper_base = self.nester or "pbpp::ScopedEnumDummy"

            self.block.write_code("struct %s : %s {" %
                                  (method_holder, method_wrapper_base))
        else:
            self.block.write_code("struct %s {" % method_holder)

        self.block.append_blank_line()

        self._generate_constructors()
        self._generate_destructor()
        self._generate_methods()
        self._generate_enums()
        self._generate_fields()

        self.block.write_code(
            Code.Snippets.method_holder_end % {
                "METHOD_HOLDER": self.namer.method_holder(self.full_name),
                "METHODS_TABLE": self.namer.methods_table(self.full_name),
                "GETSET_TABLE": self.namer.getset_table(self.full_name),
                "BASES_REGISTER": self.namer.bases_register(self.full_name),
            })

        self._generate_methods_table()
        self._generate_getset_table()

        self._generate_pytypeobject()
        self._generate_base_ptr_fixer()
        self._generate_bases_register()
        self._generate_register()

        Session.end()

        # TODO: Why can't do this in ctor?
        self.header_jar.add_headers(self.header_provider.klass(self.full_name))
        if self._require_wrapper_class():
            self.header_jar.add_headers(("<typeinfo>", ))

        memblock = CodeBlock.CodeBlock()

        memblock.write_code(self.header_provider.pch())
        memblock.write_code(self.header_jar.concat_sorted())
        memblock.append_blank_line()

        # TODO: a dirty trick
        self.block.lines = memblock.lines + self.block.lines

        self.modified = False