# SPDX-License-Identifier: BSD-2-Clause

# Copyright (c) 2026 Phil Thompson <phil@riverbankcomputing.com>


from abc import ABC, abstractmethod


class AbstractBackend(ABC):
    """ The abstract base class for backend code generators. """

    @staticmethod
    def factory(project):
        """ Return an appropriate backend for the target ABI. """

        if project.abi_version[0] >= 14:
            from .v14 import v14Backend as backend
        else:
            from .v12v13 import v12v13Backend as backend

        return backend()

    @abstractmethod
    def g_arg_parser(self, sf, spec, scope, py_signature, signature_nr,
            ctor=None, is_method=False, overload=None):
        """ Generate an argument parser call. """

        ...

    @abstractmethod
    def g_cast_function(self, sf, spec, klass):
        """ Generate the function that casts a C++ pointer to a target type.
        """

        ...

    @abstractmethod
    def g_catch_body(self, sf):
        """ Generate the body of a catch clause. """

        ...

    @abstractmethod
    def g_class_api(self, sf, spec, klass):
        """ Generate the API details for a class. """

        ...

    @abstractmethod
    def g_class_spec_extern_decl(self, sf, spec, klass):
        """ Generate the extern declaration of a class specification. """

        ...

    @abstractmethod
    def g_conversion_to_enum(self, sf, enum):
        """ Generate the code to convert a Python enum (sipSelf) to a C/C++
        enum (sipCpp).
        """

        ...

    @abstractmethod
    def g_cpp_dtor(self, sf):
        """ Generate the body of the dtor of a generated shadow class. """

        ...

    @abstractmethod
    def g_create_wrapped_module(self, sf, spec,
        name_cache_closure,
        has_external,
        enums_closure,
        has_virtual_error_handlers,
        nr_subclass_convertors,
        inst_state,
        has_slot_extenders,
        has_init_extenders
    ):
        """ Generate the code to create a wrapped module and return an
        ABI-specific object that will be passed back to the backend at some
        point. """

        # Note that some of the arguments are backend-specific and the
        # corresponding code could be generated within the backends
        # implementation of this function.  We do it this way (at least for
        # now) to ensure that the code generated by the legacy backend is
        # identical to that generated before backends were introduced.
        ...

    @abstractmethod
    def g_enums_specifications(self, sf, spec, scope=None):
        """ Generate the specifications for the wrapped enums in a scope and
        return an ABI-specific object which will be passed back to the backend
        at some point.
        """

        ...

    def g_exceptions_specifications(self, sf, spec):
        """ Generate the specifications for any exceptions. """

        # This default implementation does nothing.
        pass

    @abstractmethod
    def g_exceptions_decls(self, sf, spec):
        """ Generate the declarations of all exceptions. """

        ...

    def g_exceptions_defn(self, sf, spec):
        """ Generate the definition of the exceptions data structure. """

        # This default implementation does nothing.
        pass

    @abstractmethod
    def g_externals(self, sf, spec):
        """ Generate the external types.  Return an ABI-specific object which
        will be passed back to the backend at some point.
        """

        ...

    @abstractmethod
    def g_get_py_reimpl(self, sf, spec, klass, overload, virt_nr):
        """ Generate the code to get the Python reimplementation of a C++
        virtual.
        """

        ...

    @abstractmethod
    def g_import_tables(self, sf, spec):
        """ Generated the tables related to imported modules. """

        ...

    @abstractmethod
    def g_imported_module_decls(self, sf, spec, imported_module):
        """ Generate any declarations related to an imported module. """

        ...

    @abstractmethod
    def g_init_extenders_table(self, sf, spec):
        """ Generate the init extenders table. """

        ...

    @abstractmethod
    def g_mapped_type_api(self, sf, spec, mapped_type):
        """ Generate the API details for a mapped type. """

        ...

    @abstractmethod
    def g_mapped_type_definition(self, sf, spec, mapped_type):
        """ Generate the type structure that contains all the information
        needed by a mapped type.
        """

        ...

    @abstractmethod
    def g_method_error_handler_end(sf, overload):
        """ Generate the end of the error handling of a method. """

        ...

    @abstractmethod
    def g_method_error_handler_start(self, sf, overload, error_value):
        """ Generate the start of the error handling of a method. """

        ...

    def g_mixin_support(self, sf, spec, klass):
        """ Generate the support for mixins. """

        # This default implementation does nothing.
        pass

    @abstractmethod
    def g_module_definition(self, sf, spec, has_module_functions=False):
        """ Generate the module definition structure. """

        ...

    @abstractmethod
    def g_module_init_start(self, sf, spec):
        """ Generate the start of the Python module initialisation function.
        """

    def g_name_cache(self, sf, spec):
        """ Generate the name cache definition and return an ABI-specific
        object which will be passed back to the backend at some point.
        """

        # This default implementation returns None.
        return None

    @abstractmethod
    def g_not_implemented(self, sf):
        """ Generate the code to clear any exception and return
        Py_NotImplemented.
        """

        ...

    @abstractmethod
    def g_other_members(self, sf, spec, scope, members):
        """ Generate other (backend-specific) members for a scope. """

        ...

    @abstractmethod
    def g_py_method_end(self, sf, state, nr_signatures):
        """ Generate the end of a method implementation. """

        ...

    @abstractmethod
    def g_py_method_start(self, sf, spec, scope, member, original_scope,
            need_args, need_self):
        """ Generate the start of a method implementation and return an
        ABI-specific object which will be passed to g_py_method_end().
        """

        ...

    def g_py_method_support_vars(self, sf, scope):
        """ Generate the variables needed by a method implementation. """

        # This default implementation does nothing.
        pass

    @abstractmethod
    def g_sip_api(self, sf, spec, module_closure):
        """ Generate the SIP API as seen by generated code. """

        ...

    @abstractmethod
    def g_slot_extender_impl(self, sf, spec, member, klass=None):
        """ Generate the implementation of a slot extender. """

        ...

    @abstractmethod
    def g_slot_extenders_table(self, sf, spec):
        """ Generate the table of slot implementations. """

        ...

    @abstractmethod
    def g_static_function_end(self, sf, state, nr_signatures):
        """ Generate the end of a static function implementation. """

        ...

    @abstractmethod
    def g_static_function_start(self, sf, spec, scope_py, member, overloads):
        """ Generate the start of a static function implementation and return
        an ABI-specific object which will be passed to g_static_function_end().
        """

        ...

    def g_static_function_support_vars(self, sf, spec, scope):
        """ Generate the variables needed by a static function implementation.
        """

        # This default implementation does nothing.
        pass

    @abstractmethod
    def g_static_variables_table(self, sf, spec, scope=None):
        """ Generate the tables of static variables for a scope and return a
        set of strings corresponding to the tables actually generated.
        """

        ...

    @abstractmethod
    def g_subclass_convertor(self, sf, spec, klass):
        """ Generate a sub-class convertor. """

        ...

    @abstractmethod
    def g_subclass_convertors_table(self, sf, spec):
        """ Generate the table of sub-class convertors. """

        ...

    @abstractmethod
    def g_type_definition(self, sf, spec, klass):
        """ Generate the type structure that contains all the information
        needed by the meta-type.  A sub-set of this is used to extend
        namespaces.
        """

        ...

    @abstractmethod
    def g_type_init(self, sf, spec, klass, need_self, need_owner):
        """ Generate the code that initialises a type. """

        ...

    @abstractmethod
    def g_types_table(self, sf, spec, enums_state):
        """ Generate the types table for a module. """

        ...

    @abstractmethod
    def g_virt_error_handler_decls(self, sf, spec):
        """ Generate the declarations of any locally defined virtual error
        handlers.
        """

        ...

    @abstractmethod
    def g_virt_error_handler_impl(self, sf, spec, virtual_error_handler):
        """ Generate the implementations of any locally defined virtual error
        handlers.
        """

        ...

    @abstractmethod
    def g_wrapper_ref_decl(self, sf):
        """ Generate the code that declares a wrapper reference. """

        ...

    @abstractmethod
    def g_wrapper_ref_set(self, sf):
        """ Generate the code that sets the value of a wrapper reference. """

        ...

    def abi_has_deprecated_message(self, spec):
        """ Return True if the ABI implements sipDeprecated() with a message.
        """

        return True

    def abi_has_next_exception_handler(self, spec):
        """ Return True if the ABI implements sipNextExceptionHandler(). """

        return True

    def abi_has_working_char_conversion(self, spec):
        """ Return True if the ABI has working char to/from a Python integer
        converters (ie. char is not assumed to be signed).
        """

        return True

    def abi_supports_array(self, spec):
        """ Return True if the ABI supports sip.array. """

        return True

    @abstractmethod
    def abi_supports_custom_enums(self, spec):
        """ Return True if the ABI supports custom enums. """

        ...

    @abstractmethod
    def abi_supports_py_enums(self, spec):
        """ Return True if the ABI supports Python enums. """

        ...

    @abstractmethod
    def cached_name_ref(self, cached_name, as_nr=False):
        """ Return a reference to a cached name. """

        ...

    @abstractmethod
    def get_add_exception_call(self, error_state):
        """ Return a call to sipAddException(). """

        ...

    @abstractmethod
    def get_enum_to_py_conversion(self, spec, enum, value_name):
        """ Return the code to convert a C/C++ enum to a Python object. """

        ...

    @abstractmethod
    def get_enum_ref_value(self, spec, enum):
        """ Return the value of an enum's reference. """

        ...

    @abstractmethod
    def get_error_handler_ref(self, spec, error_handler):
        """ Return a reference to an error handler. """

        ...

    @abstractmethod
    def get_error_handler_ref_type(self):
        """ Return the type of a reference to an error handler. """

        ...

    def get_module_context(self):
        """ Return the value of a module context passed as the first argument
        to many ABI calls.
        """

        # This default implementation returns nothing.
        return ''

    def get_module_context_decl(self):
        """ Return the declaration of the value of a module context passed as
        the first argument to many ABI calls.
        """

        # This default implementation returns nothing.
        return ''

    @abstractmethod
    def get_raise_unknown_exception(self):
        """ Return the call to raise an exception about an unknown exception.
        """

        ...

    @abstractmethod
    def get_result_parser(self):
        """ Return the name of the Python reimplementation result parser. """

        ...

    @abstractmethod
    def get_sipself_test(self, spec, klass):
        """ Return the code that checks if 'sipSelf' was bound or passed as an
        argument.
        """

        ...

    @abstractmethod
    def get_slot_ref(self, slot_type):
        """ Return a reference to a slot. """

        ...

    @abstractmethod
    def get_spec_suffix(self):
        """ Return the suffix used for immutable specifications. """

        ...

    @abstractmethod
    def get_type_ref(self, wrapped_object):
        """ Return the reference to the type of a wrapped object. """

        ...

    @abstractmethod
    def get_wrapper_ref_init(self):
        """ Return the initialisation of a wrapper reference. """

        ...

    def need_deprecated_error_flag(self, code):
        """ Return True if the deprecated error flag is needed by some
        handwritten code.
        """

        return False
