def generate_intermediate_tree_classes():
    # Generate a "middle layer" of gcc.Tree subclasses, corresponding to most of the
    # values of
    #    enum_tree_code_class
    # from GCC's tree.h
    global modinit_preinit
    global modinit_postinit

    for code_type in type_for_code_class.values():
        # We've already built the base class:
        if code_type == "PyGccTree_TypeObj":
            continue

        # Strip off the "PyGcc" prefix and "_TypeObj" suffix:
        localname = code_type[5:-8]

        getsettable = PyGetSetDefTable("gcc_%s_getset_table" % localname, [])

        methods = PyMethodTable("gcc_%s_methods" % localname, [])

        pytype = PyGccWrapperTypeObject(
            identifier=code_type,
            localname=localname,
            tp_name="gcc.%s" % localname,
            struct_name="PyGccTree",
            tp_new="PyType_GenericNew",
            tp_base="&PyGccTree_TypeObj",
            tp_getset=getsettable.identifier,
            tp_methods=methods.identifier,
        )

        def add_simple_getter(name, c_expression, doc):
            getsettable.add_gsdef(
                name, cu.add_simple_getter("PyGcc%s_get_%s" % (localname, name), "PyGccTree", c_expression), None, doc
            )

        if localname == "Declaration":
            cu.add_defn(
                """
PyObject *
PyGccDeclaration_get_name(struct PyGccTree *self, void *closure)
{
    if (DECL_NAME(self->t.inner)) {
        return PyGccString_FromString(IDENTIFIER_POINTER (DECL_NAME (self->t.inner)));
    }
    Py_RETURN_NONE;
}

static PyObject *
PyGccDeclaration_get_location(struct PyGccTree *self, void *closure)
{
    return PyGccLocation_New(gcc_decl_get_location(PyGccTree_as_gcc_decl(self)));
}
"""
            )

            getsettable.add_gsdef("name", "PyGccDeclaration_get_name", None, "The name of this declaration (string)")
            getsettable.add_gsdef(
                "location", "PyGccDeclaration_get_location", None, "The gcc.Location for this declaration"
            )
            add_simple_getter(
                "is_artificial",
                "PyBool_FromLong(gcc_decl_is_artificial(PyGccTree_as_gcc_decl(self)))",
                "Is this a compiler-generated entity?",
            )
            add_simple_getter(
                "is_builtin",
                "PyBool_FromLong(gcc_decl_is_builtin(PyGccTree_as_gcc_decl(self)))",
                "Is this declaration built in by the compiler?",
            )
            pytype.tp_repr = "(reprfunc)PyGccDeclaration_repr"

        if localname == "Type":
            add_simple_getter(
                "name",
                "PyGccTree_New(gcc_type_get_name(PyGccTree_as_gcc_type(self)))",
                "The name of the type as a gcc.Tree, or None",
            )
            add_simple_getter(
                "pointer",
                "PyGccPointerType_New(gcc_type_get_pointer(PyGccTree_as_gcc_type(self)))",
                "The gcc.PointerType representing '(this_type *)'",
            )
            getsettable.add_gsdef(
                "attributes", "PyGccType_get_attributes", None, "The user-defined attributes on this type"
            )
            getsettable.add_gsdef("sizeof", "PyGccType_get_sizeof", None, "sizeof() this type, as a gcc.IntegerCst")

            def add_type(c_expr_for_node, typename):
                # Expose the given global type node within the gcc.Tree API
                #
                # The table is populated by tree.c:build_common_builtin_nodes
                # but unfortunately this seems to be called after our plugin is
                # initialized.
                #
                # Hence we add them as properties, so that they can be looked up on
                # demand, rather than trying to look them up once when the module
                # is set up
                cu.add_defn(
                    """
PyObject*
%s(PyObject *cls, PyObject *args)
{
    return PyGccTree_New(gcc_private_make_tree(%s));
}
"""
                    % ("PyGccType_get_%s" % typename, c_expr_for_node)
                )
                if typename == "size_t":
                    desc = typename
                else:
                    desc = typename.replace("_", " ")
                methods.add_method(
                    "%s" % typename,
                    "PyGccType_get_%s" % typename,
                    "METH_CLASS|METH_NOARGS",
                    "The builtin type '%s' as a gcc.Type (or None at startup before any compilation passes)" % desc,
                )

            # Add the standard C integer types as properties.
            #
            # Tree nodes for the standard C integer types are defined in tree.h by
            #    extern GTY(()) tree integer_types[itk_none];
            # with macros to look into it of this form:
            #       #define unsigned_type_node    integer_types[itk_unsigned_int]
            #
            std_types = [
                "itk_char",
                "itk_signed_char",
                "itk_unsigned_char",
                "itk_short",
                "itk_unsigned_short",
                "itk_int",
                "itk_unsigned_int",
                "itk_long",
                "itk_unsigned_long",
                "itk_long_long",
                "itk_unsigned_long_long",
            ]
            if GCCPLUGINS_API_VERSION < 5000:
                # int128 seems to have gone away in
                # 9f75f0266e3611513f196c898088e2712a71eaf4, discussed at
                # https://gcc.gnu.org/ml/gcc-patches/2014-08/msg01396.html
                std_types += ["itk_int128", "itk_unsigned_int128"]
            for std_type in std_types:
                # strip off the "itk_" prefix
                assert std_type.startswith("itk_")
                stddef = std_type[4:]
                # add_simple_getter(stddef,
                #                  'PyGccTree_New(gcc_private_make_tree(integer_types[%s]))' % std_type,
                #                  "The builtin type '%s' as a gcc.Type (or None at startup before any compilation passes)" % stddef.replace('_', ' '))
                add_type("integer_types[%s]" % std_type, stddef)

            # Similarly,
            #   extern GTY(()) tree global_trees[TI_MAX];
            # holds various nodes, including many with a _TYPE suffix.
            # Here are some of them:
            for ti in (
                "TI_UINT32_TYPE",
                "TI_UINT64_TYPE",
                "TI_FLOAT_TYPE",
                "TI_DOUBLE_TYPE",
                "TI_LONG_DOUBLE_TYPE",
                "TI_VOID_TYPE",
                "TI_SIZE_TYPE",
            ):
                # strip off the "TI_" prefix and "_TYPE" suffix:
                assert ti.startswith("TI_")
                assert ti.endswith("_TYPE")

                if ti == "TI_SIZE_TYPE":
                    name = "size_t"
                else:
                    name = ti[3:-5].lower()
                add_type("global_trees[%s]" % ti, name)

        if localname == "Unary":
            add_simple_getter(
                "operand",
                "PyGccTree_New(gcc_unary_get_operand(PyGccTree_as_gcc_unary(self)))",
                "The operand of this expression, as a gcc.Tree",
            )

        # Corresponds to this gcc/tree.h macro:
        #   #define IS_EXPR_CODE_CLASS(CLASS)\
        #       ((CLASS) >= tcc_reference && (CLASS) <= tcc_expression)
        if localname in ("Reference", "Comparison", "Unary", "Binary", "Statement" "VlExp", "Expression"):
            add_simple_getter(
                "location",
                (
                    "PyGccLocation_New(gcc_%s_get_location(PyGccTree_as_gcc_%s(self)))"
                    % (localname.lower(), localname.lower())
                ),
                "The source location of this expression",
            )

            methods.add_method(
                "get_symbol",
                "PyGccTree_get_symbol",  # they all share the implementation
                "METH_CLASS|METH_NOARGS",
                "FIXME",
            )

        cu.add_defn(methods.c_defn())
        cu.add_defn(getsettable.c_defn())
        cu.add_defn(pytype.c_defn())
        modinit_preinit += pytype.c_invoke_type_ready()
        modinit_postinit += pytype.c_invoke_add_to_module()
def generate_intermediate_tree_classes():
    # Generate a "middle layer" of gcc.Tree subclasses, corresponding to most of the
    # values of
    #    enum_tree_code_class
    # from GCC's tree.h
    global modinit_preinit
    global modinit_postinit

    
    for code_type in type_for_code_class.values():
        # We've already built the base class:
        if code_type == 'gcc_TreeType':
            continue

        # Strip off the "gcc_" prefix and "Type" suffix:
        localname = code_type[4:-4]

        getsettable = PyGetSetDefTable('gcc_%s_getset_table' % localname, [])

        methods = PyMethodTable('gcc_%s_methods' % localname, [])

        pytype = PyGccWrapperTypeObject(identifier = code_type,
                              localname = localname,
                              tp_name = 'gcc.%s' % localname,
                              struct_name = 'PyGccTree',
                              tp_new = 'PyType_GenericNew',
                              tp_base = '&gcc_TreeType',
                              tp_getset = getsettable.identifier,
                              tp_methods = methods.identifier)

        def add_simple_getter(name, c_expression, doc):
            getsettable.add_gsdef(name,
                                  cu.add_simple_getter('gcc_%s_get_%s' % (localname, name),
                                                       'PyGccTree',
                                                       c_expression),
                                  None,
                                  doc)

        if localname == 'Declaration':
            cu.add_defn("""
PyObject *
gcc_Declaration_get_name(struct PyGccTree *self, void *closure)
{
    if (DECL_NAME(self->t)) {
        return gcc_python_string_from_string(IDENTIFIER_POINTER (DECL_NAME (self->t)));
    }
    Py_RETURN_NONE;
}

static PyObject *
gcc_Declaration_get_location(struct PyGccTree *self, void *closure)
{
    return gcc_python_make_wrapper_location(DECL_SOURCE_LOCATION(self->t));
}
""")

            getsettable.add_gsdef('name',
                                  'gcc_Declaration_get_name',
                                  None,
                                  'The name of this declaration (string)')
            getsettable.add_gsdef('location',
                                  'gcc_Declaration_get_location',
                                  None,
                                  'The gcc.Location for this declaration')
            add_simple_getter('is_artificial',
                              'PyBool_FromLong(DECL_ARTIFICIAL(self->t))',
                              "Is this a compiler-generated entity?")
            add_simple_getter('is_builtin',
                              'PyBool_FromLong(DECL_IS_BUILTIN(self->t))',
                              "Is this declaration built in by the compiler?")
            pytype.tp_repr = '(reprfunc)gcc_Declaration_repr'

        if localname == 'Type':
            add_simple_getter('name',
                              'gcc_python_make_wrapper_tree(TYPE_NAME(self->t))',
                              "The name of the type as a gcc.Tree, or None")
            add_simple_getter('pointer',
                              'gcc_python_make_wrapper_tree(build_pointer_type(self->t))',
                              "The gcc.PointerType representing '(this_type *)'")
            getsettable.add_gsdef('attributes',
                                  'gcc_Type_get_attributes',
                                  None,
                                  'The user-defined attributes on this type')
            getsettable.add_gsdef('sizeof',
                                  'gcc_Type_get_sizeof',
                                  None,
                                  'sizeof() this type, as a gcc.IntegerCst')

            def add_type(c_expr_for_node, typename):
                # Expose the given global type node within the gcc.Tree API
                #
                # The table is populated by tree.c:build_common_builtin_nodes
                # but unfortunately this seems to be called after our plugin is
                # initialized.
                #
                # Hence we add them as properties, so that they can be looked up on
                # demand, rather than trying to look them up once when the module
                # is set up
                cu.add_defn("""
PyObject*
%s(PyObject *cls, PyObject *args)
{
    return gcc_python_make_wrapper_tree(%s);
}
"""                         % ('gcc_Type_get_%s' % typename, c_expr_for_node))
                if typename == 'size_t':
                    desc = typename
                else:
                    desc = typename.replace('_', ' ')
                methods.add_method('%s' % typename,
                                   'gcc_Type_get_%s' % typename,
                                   'METH_CLASS|METH_NOARGS',
                                   "The builtin type '%s' as a gcc.Type (or None at startup before any compilation passes)" % desc)

            # Add the standard C integer types as properties.
            #
            # Tree nodes for the standard C integer types are defined in tree.h by
            #    extern GTY(()) tree integer_types[itk_none];
            # with macros to look into it of this form:
            #       #define unsigned_type_node    integer_types[itk_unsigned_int]
            #
            for std_type in ('itk_char', 'itk_signed_char',
                             'itk_unsigned_char', 'itk_short',
                             'itk_unsigned_short', 'itk_int',
                             'itk_unsigned_int', 'itk_long',
                             'itk_unsigned_long', 'itk_long_long',
                             'itk_unsigned_long_long', 'itk_int128',
                             'itk_unsigned_int128'):
                # strip off the "itk_" prefix
                assert std_type.startswith('itk_')
                stddef = std_type[4:]
                #add_simple_getter(stddef,
                #                  'gcc_python_make_wrapper_tree(integer_types[%s])' % std_type,
                #                  "The builtin type '%s' as a gcc.Type (or None at startup before any compilation passes)" % stddef.replace('_', ' '))
                add_type('integer_types[%s]' % std_type, stddef)

            # Similarly,
            #   extern GTY(()) tree global_trees[TI_MAX];
            # holds various nodes, including many with a _TYPE suffix.
            # Here are some of them:
            for ti in ('TI_UINT32_TYPE', 'TI_UINT64_TYPE',
                       'TI_FLOAT_TYPE', 'TI_DOUBLE_TYPE',
                       'TI_LONG_DOUBLE_TYPE', 'TI_VOID_TYPE', 'TI_SIZE_TYPE'):
                # strip off the "TI_" prefix and "_TYPE" suffix:
                assert ti.startswith('TI_')
                assert ti.endswith('_TYPE')

                if ti == 'TI_SIZE_TYPE':
                    name = 'size_t'
                else:
                    name = ti[3:-5].lower()
                add_type('global_trees[%s]' % ti, name)

        if localname == 'Unary':
            add_simple_getter('operand',
                              'gcc_python_make_wrapper_tree(TREE_OPERAND (self->t, 0))',
                              'The operand of this expression, as a gcc.Tree')

        # Corresponds to this gcc/tree.h macro:
        #   #define IS_EXPR_CODE_CLASS(CLASS)\
        #       ((CLASS) >= tcc_reference && (CLASS) <= tcc_expression)
        if localname in ('Reference', 'Comparison', 'Unary', 'Binary',
                         'Statement' 'VlExp', 'Expression'):
            add_simple_getter('location',
                              'gcc_python_make_wrapper_location(EXPR_LOCATION(self->t))',
                              "The source location of this expression")

            methods.add_method('get_symbol',
                               'gcc_Tree_get_symbol', # they all share the implementation
                               'METH_CLASS|METH_NOARGS',
                               "FIXME")

        cu.add_defn(methods.c_defn())
        cu.add_defn(getsettable.c_defn())            
        cu.add_defn(pytype.c_defn())
        modinit_preinit += pytype.c_invoke_type_ready()
        modinit_postinit += pytype.c_invoke_add_to_module()