def generate_tree_code_classes():
    # Generate all of the concrete gcc.Tree subclasses based on the:
    #    enum tree_code
    # as subclasses of the above layer:
    global modinit_preinit
    global modinit_postinit

    for tree_type in tree_types:
        base_type = type_for_code_class[tree_type.TYPE]

        cc = tree_type.camel_cased_string()

        getsettable = PyGetSetDefTable(
            "gcc_%s_getset_table" % cc, [], identifier_prefix="gcc_%s" % cc, typename="PyGccTree"
        )

        tp_as_number = None
        tp_repr = None
        tp_str = None

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

        def get_getter_identifier(name):
            return "PyGcc%s_get_%s" % (cc, name)

        def add_simple_getter(name, c_expression, doc):
            getsettable.add_gsdef(
                name, cu.add_simple_getter(get_getter_identifier(name), "PyGccTree", c_expression), None, doc
            )

        def add_complex_getter(name, doc):
            getsettable.add_gsdef(name, get_getter_identifier(name), None, doc)

        if cc == "AddrExpr":
            add_simple_getter(
                "operand",
                "PyGccTree_New(gcc_addr_expr_get_operand(PyGccTree_as_gcc_addr_expr(self)))",
                "The operand of this expression, as a gcc.Tree",
            )

        if cc == "StringCst":
            add_simple_getter(
                "constant",
                "PyGccString_FromString(gcc_string_constant_get_char_ptr(PyGccTree_as_gcc_string_constant(self)))",
                "The actual value of this constant, as a str",
            )
            tp_repr = "(reprfunc)PyGccStringConstant_repr"

        if cc == "IntegerCst":
            getsettable.add_gsdef(
                "constant",
                "PyGccIntegerConstant_get_constant",
                None,
                "The actual value of this constant, as an int/long",
            )
            number_methods = PyNumberMethods("PyGccIntegerConstant_number_methods")
            tp_as_number = number_methods.identifier
            number_methods.nb_int = "PyGccIntegerConstant_get_constant"
            cu.add_defn(number_methods.c_defn())
            tp_repr = "(reprfunc)PyGccIntegerConstant_repr"

        if cc == "RealCst":
            getsettable.add_gsdef(
                "constant", "PyGccRealCst_get_constant", None, "The actual value of this constant, as a float"
            )
            tp_repr = "(reprfunc)PyGccRealCst_repr"

        # TYPE_QUALS for various foo_TYPE classes:
        if tree_type.SYM in (
            "VOID_TYPE",
            "INTEGER_TYPE",
            "REAL_TYPE",
            "FIXED_POINT_TYPE",
            "COMPLEX_TYPE",
            "VECTOR_TYPE",
            "ENUMERAL_TYPE",
            "BOOLEAN_TYPE",
        ):
            for qual in ("const", "volatile", "restrict"):
                add_simple_getter(
                    qual,
                    "PyBool_FromLong(TYPE_QUALS(self->t.inner) & TYPE_QUAL_%s)" % qual.upper(),
                    "Boolean: does this type have the '%s' modifier?" % qual,
                )
                add_simple_getter(
                    "%s_equivalent" % qual,
                    "PyGccTree_New(gcc_private_make_tree(build_qualified_type(self->t.inner, TYPE_QUAL_%s)))"
                    % qual.upper(),
                    "The gcc.Type for the %s version of this type" % qual,
                )
        if tree_type.SYM == "RECORD_TYPE":
            add_simple_getter(
                "const",
                "PyBool_FromLong(TYPE_READONLY(self->t.inner))",
                "Boolean: does this type have the 'const' modifier?",
            )

        if tree_type.SYM == "INTEGER_TYPE":
            add_simple_getter(
                "unsigned",
                "PyBool_FromLong(gcc_integer_type_is_unsigned(PyGccTree_as_gcc_integer_type(self)))",
                "Boolean: True for 'unsigned', False for 'signed'",
            )
            add_complex_getter("signed_equivalent", "The gcc.IntegerType for the signed version of this type")
            add_complex_getter("unsigned_equivalent", "The gcc.IntegerType for the unsigned version of this type")
            add_simple_getter(
                "max_value",
                "PyGccTree_New(gcc_integer_constant_as_gcc_tree(gcc_integer_type_get_max_value(PyGccTree_as_gcc_integer_type(self))))",
                "The maximum possible value for this type, as a gcc.IntegerCst",
            )
            add_simple_getter(
                "min_value",
                "PyGccTree_New(gcc_integer_constant_as_gcc_tree(gcc_integer_type_get_min_value(PyGccTree_as_gcc_integer_type(self))))",
                "The minimum possible value for this type, as a gcc.IntegerCst",
            )
            tp_repr = "(reprfunc)PyGccIntegerType_repr"

        if tree_type.SYM in ("INTEGER_TYPE", "REAL_TYPE", "FIXED_POINT_TYPE"):
            prefix = "gcc_%s" % tree_type.SYM.lower()
            add_simple_getter(
                "precision",
                "PyGccInt_FromLong(%s_get_precision(PyGccTree_as_%s(self)))" % (prefix, prefix),
                "The precision of this type in bits, as an int (e.g. 32)",
            )

        if tree_type.SYM in ("POINTER_TYPE", "ARRAY_TYPE", "VECTOR_TYPE"):
            prefix = "gcc_%s" % tree_type.SYM.lower()
            add_simple_getter(
                "dereference",
                ("PyGccTree_New(gcc_type_as_gcc_tree(%s_get_dereference(PyGccTree_as_%s(self))))" % (prefix, prefix)),
                "The gcc.Type that this type points to'",
            )

        if tree_type.SYM == "POINTER_TYPE":
            tp_repr = "(reprfunc)PyGccPointerType_repr"

        if tree_type.SYM == "ARRAY_TYPE":
            add_simple_getter(
                "range",
                "PyGccTree_New(gcc_private_make_tree(TYPE_DOMAIN(self->t.inner)))",
                "The gcc.Type that is the range of this array type",
            )

        if tree_type.SYM == "ARRAY_REF":
            add_simple_getter(
                "array",
                "PyGccTree_New(gcc_array_ref_get_array(PyGccTree_as_gcc_array_ref(self)))",
                "The gcc.Tree for the array being referenced'",
            )
            add_simple_getter(
                "index",
                "PyGccTree_New(gcc_array_ref_get_index(PyGccTree_as_gcc_array_ref(self)))",
                "The gcc.Tree for index being referenced'",
            )
            tp_repr = "(reprfunc)PyGccArrayRef_repr"

        if tree_type.SYM == "COMPONENT_REF":
            add_simple_getter(
                "target",
                "PyGccTree_New(gcc_component_ref_get_target(PyGccTree_as_gcc_component_ref(self)))",
                "The gcc.Tree that for the container of the field'",
            )
            add_simple_getter(
                "field",
                "PyGccTree_New(gcc_component_ref_get_field(PyGccTree_as_gcc_component_ref(self)))",
                "The gcc.FieldDecl for the field within the target'",
            )
            tp_repr = "(reprfunc)PyGccComponentRef_repr"

        if tree_type.SYM == "MEM_REF":
            add_simple_getter(
                "operand",
                "PyGccTree_New(gcc_mem_ref_get_operand(PyGccTree_as_gcc_mem_ref(self)))",
                "The gcc.Tree that for the pointer expression'",
            )

        if tree_type.SYM == "BIT_FIELD_REF":
            add_simple_getter(
                "operand",
                "PyGccTree_New(gcc_private_make_tree(TREE_OPERAND(self->t.inner, 0)))",
                "The gcc.Tree for the structure or union expression",
            )
            add_simple_getter(
                "num_bits",
                "PyGccTree_New(gcc_private_make_tree(TREE_OPERAND(self->t.inner, 1)))",
                "The number of bits being referenced, as a gcc.IntegerCst",
            )
            add_simple_getter(
                "position",
                "PyGccTree_New(gcc_private_make_tree(TREE_OPERAND(self->t.inner, 2)))",
                "The position of the first referenced bit, as a gcc.IntegerCst",
            )

        if tree_type.SYM in ("RECORD_TYPE", "UNION_TYPE", "QUAL_UNION_TYPE"):
            add_simple_getter(
                "fields", "PyGcc_TreeListFromChain(TYPE_FIELDS(self->t.inner))", "The fields of this type"
            )
            add_simple_getter(
                "methods", "PyGcc_TreeListFromChain(TYPE_METHODS(self->t.inner))", "The methods of this type"
            )

        if tree_type.SYM == "IDENTIFIER_NODE":
            add_simple_getter(
                "name",
                "PyGccStringOrNone(IDENTIFIER_POINTER(self->t.inner))",
                "The name of this gcc.IdentifierNode, as a string",
            )
            tp_repr = "(reprfunc)PyGccIdentifierNode_repr"

        if tree_type.SYM == "VAR_DECL":
            add_simple_getter(
                "initial",
                "PyGccTree_New(gcc_constructor_as_gcc_tree(gcc_var_decl_get_initial(PyGccTree_as_gcc_var_decl(self))))",
                "The initial value for this variable as a gcc.Constructor, or None",
            )
            add_simple_getter(
                "static",
                "PyBool_FromLong(gcc_var_decl_is_static(PyGccTree_as_gcc_var_decl(self)))",
                "Boolean: is this variable to be allocated with static storage",
            )

        if tree_type.SYM == "CONSTRUCTOR":
            add_complex_getter("elements", "The elements of this constructor, as a list of (index, gcc.Tree) pairs")

        if tree_type.SYM == "TRANSLATION_UNIT_DECL":
            add_simple_getter(
                "block",
                "PyGccBlock_New(gcc_translation_unit_decl_get_block(PyGccTree_as_gcc_translation_unit_decl(self)))",
                "The gcc.Block for this namespace",
            )
            add_simple_getter(
                "language",
                "PyGccString_FromString(gcc_translation_unit_decl_get_language(PyGccTree_as_gcc_translation_unit_decl(self)))",
                "The source language of this translation unit, as a string",
            )

        if tree_type.SYM == "BLOCK":
            add_simple_getter(
                "vars",
                "PyGcc_TreeListFromChain(BLOCK_VARS(self->t.inner))",
                "The list of gcc.Tree for the declarations and labels in this block",
            )

        if tree_type.SYM == "NAMESPACE_DECL":
            add_simple_getter(
                "alias_of",
                "PyGccTree_New(gcc_private_make_tree(DECL_NAMESPACE_ALIAS(self->t.inner)))",
                "None if not an alias, otherwise the gcc.NamespaceDecl we alias",
            )
            add_simple_getter(
                "declarations",
                "PyGccNamespaceDecl_declarations(self->t.inner)",
                "The list of gcc.Declarations within this namespace",
            )
            add_simple_getter(
                "namespaces",
                "PyGccNamespaceDecl_namespaces(self->t.inner)",
                "The list of gcc.NamespaceDecl objects and gcc.TypeDecl of Unions nested in this namespace",
            )
            methods.add_method(
                "lookup",
                "(PyCFunction)PyGccNamespaceDecl_lookup",
                "METH_VARARGS|METH_KEYWORDS",
                "Look up the given string within this namespace",
            )
            methods.add_method(
                "unalias",
                "(PyCFunction)PyGccNamespaceDecl_unalias",
                "METH_VARARGS|METH_KEYWORDS",
                "A gcc.NamespaceDecl of this namespace that is not an alias",
            )

        if tree_type.SYM == "TYPE_DECL":
            getsettable.add_gsdef(
                "pointer", "PyGccTypeDecl_get_pointer", None, "The gcc.PointerType representing '(this_type *)'"
            )

        if tree_type.SYM == "FUNCTION_TYPE":
            getsettable.add_gsdef(
                "argument_types",
                "PyGccFunction_TypeObj_get_argument_types",
                None,
                "A tuple of gcc.Type instances, representing the argument types of this function type",
            )

        if tree_type.SYM == "METHOD_TYPE":
            getsettable.add_gsdef(
                "argument_types",
                "PyGccMethodType_get_argument_types",
                None,
                "A tuple of gcc.Type instances, representing the argument types of this method type",
            )

        if tree_type.SYM == "FUNCTION_DECL":
            getsettable.add_gsdef(
                "fullname",
                "PyGccFunctionDecl_get_fullname",
                None,
                "C++ only: the full name of this function declaration",
            )
            add_simple_getter(
                "function",
                "PyGccFunction_New(gcc_private_make_function(DECL_STRUCT_FUNCTION(self->t.inner)))",
                "The gcc.Function (or None) for this declaration",
            )
            add_simple_getter(
                "arguments", "PyGcc_TreeListFromChain(DECL_ARGUMENTS(self->t.inner))", "List of gcc.ParmDecl"
            )
            add_simple_getter(
                "result",
                "PyGccTree_New(gcc_private_make_tree(DECL_RESULT_FLD(self->t.inner)))",
                "The gcc.ResultDecl for the return value",
            )
            getsettable.add_gsdef(
                "callgraph_node",
                "PyGccFunctionDecl_get_callgraph_node",
                None,
                "The gcc.CallgraphNode for this function declaration, or None",
            )

            for attr in ("public", "private", "protected", "static"):
                getsettable.add_simple_getter(
                    cu, "is_%s" % attr, "PyBool_FromLong(TREE_%s(self->t.inner))" % attr.upper(), None
                )

        if tree_type.SYM == "SSA_NAME":
            # c.f. "struct GTY(()) tree_ssa_name":
            add_simple_getter(
                "var",
                "PyGccTree_New(gcc_ssa_name_get_var(PyGccTree_as_gcc_ssa_name(self)))",
                "The variable being referenced'",
            )
            add_simple_getter(
                "def_stmt",
                "PyGccGimple_New(gcc_ssa_name_get_def_stmt(PyGccTree_as_gcc_ssa_name(self)))",
                "The gcc.Gimple statement which defines this SSA name'",
            )
            add_simple_getter(
                "version",
                "PyGccInt_FromLong(gcc_ssa_name_get_version(PyGccTree_as_gcc_ssa_name(self)))",
                "The SSA version number of this SSA name'",
            )
            tp_repr = "(reprfunc)PyGccSsaName_repr"

        if tree_type.SYM == "TREE_LIST":
            # c.f. "struct GTY(()) tree_list":
            tp_repr = "(reprfunc)PyGccTreeList_repr"

        if tree_type.SYM == "CASE_LABEL_EXPR":
            add_simple_getter(
                "low",
                "PyGccTree_New(gcc_case_label_expr_get_low(PyGccTree_as_gcc_case_label_expr(self)))",
                "The low value of the case label, as a gcc.Tree (or None for the default)",
            )
            add_simple_getter(
                "high",
                "PyGccTree_New(gcc_case_label_expr_get_high(PyGccTree_as_gcc_case_label_expr(self)))",
                "The high value of the case label, if any, as a gcc.Tree (None for the default and for single-valued case labels)",
            )
            add_simple_getter(
                "target",
                "PyGccTree_New(gcc_label_decl_as_gcc_tree(gcc_case_label_expr_get_target(PyGccTree_as_gcc_case_label_expr(self))))",
                "The target of the case label, as a gcc.LabelDecl",
            )
            tp_repr = "(reprfunc)PyGccCaseLabelExpr_repr"

        cu.add_defn(getsettable.c_defn())
        cu.add_defn(methods.c_defn())
        pytype = PyGccWrapperTypeObject(
            identifier="PyGcc%s_TypeObj" % cc,
            localname=cc,
            tp_name="gcc.%s" % cc,
            struct_name="PyGccTree",
            tp_new="PyType_GenericNew",
            tp_base="&%s" % base_type,
            tp_getset=getsettable.identifier,
            tp_str=tp_str,
            tp_repr=tp_repr,
            tp_methods=methods.identifier,
        )
        if tp_as_number:
            pytype.tp_as_number = "&%s" % tp_as_number
        cu.add_defn(pytype.c_defn())
        modinit_preinit += pytype.c_invoke_type_ready()
        modinit_postinit += pytype.c_invoke_add_to_module()

    cu.add_defn("\n/* Map from GCC tree codes to PyGccWrapperTypeObject* */\n")
    cu.add_defn("PyGccWrapperTypeObject *pytype_for_tree_code[] = {\n")
    for tree_type in tree_types:
        cu.add_defn("    &PyGcc%s_TypeObj, /* %s */\n" % (tree_type.camel_cased_string(), tree_type.SYM))
    cu.add_defn("};\n\n")

    cu.add_defn("\n/* Map from PyGccWrapperTypeObject* to GCC tree codes*/\n")
    cu.add_defn("int \n")
    cu.add_defn("PyGcc_tree_type_object_as_tree_code(PyObject *cls, enum tree_code *out)\n")
    cu.add_defn("{\n")
    for tree_type in tree_types:
        cu.add_defn(
            "    if (cls == (PyObject*)&PyGcc%s_TypeObj) {\n"
            "        *out = %s; return 0;\n"
            "    }\n" % (tree_type.camel_cased_string(), tree_type.SYM)
        )
    cu.add_defn("    return -1;\n")
    cu.add_defn("}\n")

    cu.add_defn(
        """
PyGccWrapperTypeObject*
PyGcc_autogenerated_tree_type_for_tree_code(enum tree_code code, int borrow_ref)
{
    PyGccWrapperTypeObject *result;

    assert(code >= 0);
    assert(code < MAX_TREE_CODES);

    result = pytype_for_tree_code[code];

    if (!borrow_ref) {
        Py_INCREF(result);
    }
    return result;
}

PyGccWrapperTypeObject*
PyGcc_autogenerated_tree_type_for_tree(gcc_tree t, int borrow_ref)
{
    enum tree_code code = TREE_CODE(t.inner);
    /* printf("code:%i\\n", code); */
    return PyGcc_autogenerated_tree_type_for_tree_code(code, borrow_ref);
}
"""
    )
def generate_tree_code_classes():
    # Generate all of the concrete gcc.Tree subclasses based on the:
    #    enum tree_code
    # as subclasses of the above layer:
    global modinit_preinit
    global modinit_postinit
    
    for tree_type in tree_types:
        base_type = type_for_code_class[tree_type.TYPE]

        cc = tree_type.camel_cased_string()

        getsettable =  PyGetSetDefTable('gcc_%s_getset_table' % cc, [],
                                        identifier_prefix='gcc_%s' % cc,
                                        typename='PyGccTree')

        tp_as_number = None
        tp_repr = None
        tp_str = None

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

        def get_getter_identifier(name):
            return 'gcc_%s_get_%s' % (cc, name)

        def add_simple_getter(name, c_expression, doc):
            getsettable.add_gsdef(name,
                                  cu.add_simple_getter(get_getter_identifier(name),
                                                       'PyGccTree',
                                                       c_expression),
                                  None,
                                  doc)

        def add_complex_getter(name, doc):
            getsettable.add_gsdef(name,
                                  get_getter_identifier(name),
                                  None,
                                  doc)

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

        if cc == 'StringCst':
            add_simple_getter('constant',
                              'gcc_python_string_from_string(TREE_STRING_POINTER(self->t))',
                              'The actual value of this constant, as a str')
            tp_repr = '(reprfunc)gcc_StringConstant_repr'

        if cc == 'IntegerCst':
            getsettable.add_gsdef('constant',
                                  'gcc_IntegerConstant_get_constant',
                                  None,
                                  'The actual value of this constant, as an int/long')
            number_methods = PyNumberMethods('gcc_IntegerConstant_number_methods')
            tp_as_number = number_methods.identifier
            number_methods.nb_int = 'gcc_IntegerConstant_get_constant'
            cu.add_defn(number_methods.c_defn())
            tp_repr = '(reprfunc)gcc_IntegerConstant_repr'

        if cc == 'RealCst':
            getsettable.add_gsdef('constant',
                                  'gcc_RealCst_get_constant',
                                  None,
                                  'The actual value of this constant, as a float')
            tp_repr = '(reprfunc)gcc_RealCst_repr'

        # TYPE_QUALS for various foo_TYPE classes:
        if tree_type.SYM in ('VOID_TYPE', 'INTEGER_TYPE', 'REAL_TYPE', 
                             'FIXED_POINT_TYPE', 'COMPLEX_TYPE', 'VECTOR_TYPE',
                             'ENUMERAL_TYPE', 'BOOLEAN_TYPE'):
            for qual in ('const', 'volatile', 'restrict'):
                add_simple_getter(qual,
                                  'PyBool_FromLong(TYPE_QUALS(self->t) & TYPE_QUAL_%s)' % qual.upper(),
                                  "Boolean: does this type have the '%s' modifier?" % qual)
                add_simple_getter('%s_equivalent' % qual,
                                  'gcc_python_make_wrapper_tree(build_qualified_type(self->t, TYPE_QUAL_%s))' % qual.upper(),
                                  'The gcc.Type for the %s version of this type' % qual)

        if tree_type.SYM == 'INTEGER_TYPE':
            add_simple_getter('unsigned',
                              'PyBool_FromLong(TYPE_UNSIGNED(self->t))',
                              "Boolean: True for 'unsigned', False for 'signed'")
            add_simple_getter('signed_equivalent',
                              'gcc_python_make_wrapper_tree(c_common_signed_type(self->t))',
                              'The gcc.IntegerType for the signed version of this type')
            add_simple_getter('unsigned_equivalent',
                              'gcc_python_make_wrapper_tree(c_common_unsigned_type(self->t))',
                              'The gcc.IntegerType for the unsigned version of this type')
            add_simple_getter('max_value',
                              'gcc_python_make_wrapper_tree(TYPE_MAX_VALUE(self->t))',
                              'The maximum possible value for this type, as a gcc.IntegerCst')
            add_simple_getter('min_value',
                              'gcc_python_make_wrapper_tree(TYPE_MIN_VALUE(self->t))',
                              'The minimum possible value for this type, as a gcc.IntegerCst')

        if tree_type.SYM in ('INTEGER_TYPE', 'REAL_TYPE', 'FIXED_POINT_TYPE'):
            add_simple_getter('precision',
                              'gcc_python_int_from_long(TYPE_PRECISION(self->t))',
                              'The precision of this type in bits, as an int (e.g. 32)')

        if tree_type.SYM in ('POINTER_TYPE', 'ARRAY_TYPE', 'VECTOR_TYPE'):
            add_simple_getter('dereference',
                              'gcc_python_make_wrapper_tree(TREE_TYPE(self->t))',
                              "The gcc.Type that this type points to'")

        if tree_type.SYM == 'ARRAY_TYPE':
            add_simple_getter('range',
                              'gcc_python_make_wrapper_tree(TYPE_DOMAIN(self->t))',
                              "The gcc.Type that is the range of this array type")

        if tree_type.SYM == 'ARRAY_REF':
            add_simple_getter('array',
                              'gcc_python_make_wrapper_tree(TREE_OPERAND(self->t, 0))',
                              "The gcc.Tree for the array being referenced'")
            add_simple_getter('index',
                              'gcc_python_make_wrapper_tree(TREE_OPERAND(self->t, 1))',
                              "The gcc.Tree for index being referenced'")

        if tree_type.SYM == 'COMPONENT_REF':
            add_simple_getter('target',
                              'gcc_python_make_wrapper_tree(TREE_OPERAND(self->t, 0))',
                              "The gcc.Tree that for the container of the field'")
            add_simple_getter('field',
                              'gcc_python_make_wrapper_tree(TREE_OPERAND(self->t, 1))',
                              "The gcc.FieldDecl for the field within the target'")

        if tree_type.SYM == 'MEM_REF':
            add_simple_getter('operand',
                              'gcc_python_make_wrapper_tree(TREE_OPERAND(self->t, 0))',
                              "The gcc.Tree that for the pointer expression'")

        if tree_type.SYM == 'BIT_FIELD_REF':
            add_simple_getter('operand',
                              'gcc_python_make_wrapper_tree(TREE_OPERAND(self->t, 0))',
                              "The gcc.Tree for the structure or union expression")
            add_simple_getter('num_bits',
                              'gcc_python_make_wrapper_tree(TREE_OPERAND(self->t, 1))',
                              "The number of bits being referenced, as a gcc.IntegerCst")
            add_simple_getter('position',
                              'gcc_python_make_wrapper_tree(TREE_OPERAND(self->t, 2))',
                              "The position of the first referenced bit, as a gcc.IntegerCst")

        if tree_type.SYM in ('RECORD_TYPE', 'UNION_TYPE', 'QUAL_UNION_TYPE'):
            add_simple_getter('fields',
                              'gcc_tree_list_from_chain(TYPE_FIELDS(self->t))',
                              "The fields of this type")

        if tree_type.SYM == 'IDENTIFIER_NODE':
            add_simple_getter('name',
                              'gcc_python_string_or_none(IDENTIFIER_POINTER(self->t))',
                              "The name of this gcc.IdentifierNode, as a string")
            tp_repr = '(reprfunc)gcc_IdentifierNode_repr'

        if tree_type.SYM == 'VAR_DECL':
            add_simple_getter('initial',
                              'gcc_python_make_wrapper_tree(DECL_INITIAL(self->t))',
                              "The initial value for this variable as a gcc.Constructor, or None")
            add_simple_getter('static',
                              'PyBool_FromLong(TREE_STATIC(self->t))',
                              "Boolean: is this variable to be allocated with static storage")

        if tree_type.SYM == 'CONSTRUCTOR':
            add_complex_getter('elements',
                              "The elements of this constructor, as a list of (index, gcc.Tree) pairs")

        if tree_type.SYM == 'TRANSLATION_UNIT_DECL':
            add_simple_getter('block',
                              'gcc_python_make_wrapper_tree(DECL_INITIAL(self->t))',
                               "The gcc.Block for this namespace")
            add_simple_getter('language',
                              'gcc_python_string_from_string(TRANSLATION_UNIT_LANGUAGE(self->t))',
                               "The source language of this translation unit, as a string")

        if tree_type.SYM == 'BLOCK':
            add_simple_getter('vars',
                              'gcc_tree_list_from_chain(BLOCK_VARS(self->t))',
                               "The list of gcc.Tree for the declarations and labels in this block")

        if tree_type.SYM == 'NAMESPACE_DECL':
            add_simple_getter('alias_of',
                              'gcc_python_make_wrapper_tree(DECL_NAMESPACE_ALIAS(self->t))',
                              "None if not an alias, otherwise the gcc.NamespaceDecl we alias")
            add_simple_getter('declarations',
                              'gcc_python_namespace_decl_declarations(self->t)',
                              'The list of gcc.Declarations within this namespace')
            add_simple_getter('namespaces',
                              'gcc_python_namespace_decl_namespaces(self->t)',
                              'The list of gcc.NamespaceDecl objects and gcc.TypeDecl of Unions nested in this namespace')
            methods.add_method('lookup',
                               '(PyCFunction)gcc_NamespaceDecl_lookup',
                               'METH_VARARGS|METH_KEYWORDS',
                               "Look up the given string within this namespace")
            methods.add_method('unalias',
                               '(PyCFunction)gcc_NamespaceDecl_unalias',
                               'METH_VARARGS|METH_KEYWORDS',
                               "A gcc.NamespaceDecl of this namespace that is not an alias")

        if tree_type.SYM == 'TYPE_DECL':
            getsettable.add_gsdef('pointer',
                                  'gcc_TypeDecl_get_pointer',
                                  None,
                                  "The gcc.PointerType representing '(this_type *)'")

        if tree_type.SYM == 'FUNCTION_TYPE':
            getsettable.add_gsdef('argument_types',
                                  'gcc_FunctionType_get_argument_types',
                                  None,
                                  "A tuple of gcc.Type instances, representing the argument types of this function type")

        if tree_type.SYM == 'METHOD_TYPE':
            getsettable.add_gsdef('argument_types',
                                  'gcc_MethodType_get_argument_types',
                                  None,
                                  "A tuple of gcc.Type instances, representing the argument types of this method type")

        if tree_type.SYM == 'FUNCTION_DECL':
            getsettable.add_gsdef('fullname',
                                  'gcc_FunctionDecl_get_fullname',
                                  None,
                                  'C++ only: the full name of this function declaration')
            add_simple_getter('function',
                              'gcc_python_make_wrapper_function(DECL_STRUCT_FUNCTION(self->t))',
                              'The gcc.Function (or None) for this declaration')
            add_simple_getter('arguments',
                              'gcc_tree_list_from_chain(DECL_ARGUMENTS(self->t))',
                              'List of gcc.ParmDecl')
            add_simple_getter('result',
                              'gcc_python_make_wrapper_tree(DECL_RESULT_FLD(self->t))',
                              'The gcc.ResultDecl for the return value')
            add_simple_getter('callgraph_node',
                              'gcc_python_make_wrapper_cgraph_node(cgraph_get_node(self->t))',
                              'The gcc.CallgraphNode for this function declaration, or None')

            for attr in ('public', 'private', 'protected', 'static'):
                getsettable.add_simple_getter(cu,
                                              'is_%s' % attr,
                                              'PyBool_FromLong(TREE_%s(self->t))' % attr.upper(),
                                              None)

        if tree_type.SYM == 'SSA_NAME':
            # c.f. "struct GTY(()) tree_ssa_name":
            add_simple_getter('var',
                              'gcc_python_make_wrapper_tree(SSA_NAME_VAR(self->t))',
                              "The variable being referenced'")
            add_simple_getter('def_stmt',
                              'gcc_python_make_wrapper_gimple(SSA_NAME_DEF_STMT(self->t))',
                              "The gcc.Gimple statement which defines this SSA name'")
            add_simple_getter('version',
                              'gcc_python_int_from_long(SSA_NAME_VERSION(self->t))',
                              "The SSA version number of this SSA name'")

        if tree_type.SYM == 'TREE_LIST':
            # c.f. "struct GTY(()) tree_list":
            tp_repr = '(reprfunc)gcc_TreeList_repr'

        if tree_type.SYM == 'CASE_LABEL_EXPR':
            add_simple_getter('low',
                              'gcc_python_make_wrapper_tree(CASE_LOW(self->t))',
                              "The low value of the case label, as a gcc.Tree (or None for the default)")
            add_simple_getter('high',
                              'gcc_python_make_wrapper_tree(CASE_HIGH(self->t))',
                              "The high value of the case label, if any, as a gcc.Tree (None for the default and for single-valued case labels)")
            add_simple_getter('target',
                              'gcc_python_make_wrapper_tree(CASE_LABEL(self->t))',
                              "The target of the case label, as a gcc.LabelDecl")

        cu.add_defn(getsettable.c_defn())
        cu.add_defn(methods.c_defn())
        pytype = PyGccWrapperTypeObject(identifier = 'gcc_%sType' % cc,
                              localname = cc,
                              tp_name = 'gcc.%s' % cc,
                              struct_name = 'PyGccTree',
                              tp_new = 'PyType_GenericNew',
                              tp_base = '&%s' % base_type,
                              tp_getset = getsettable.identifier,
                              tp_str = tp_str,
                              tp_repr = tp_repr,
                              tp_methods = methods.identifier,
                              )
        if tp_as_number:
            pytype.tp_as_number = '&%s' % tp_as_number
        cu.add_defn(pytype.c_defn())
        modinit_preinit += pytype.c_invoke_type_ready()
        modinit_postinit += pytype.c_invoke_add_to_module()
        

    cu.add_defn('\n/* Map from GCC tree codes to PyGccWrapperTypeObject* */\n')
    cu.add_defn('PyGccWrapperTypeObject *pytype_for_tree_code[] = {\n')
    for tree_type in tree_types:
        cu.add_defn('    &gcc_%sType, /* %s */\n' % (tree_type.camel_cased_string(), tree_type.SYM))
    cu.add_defn('};\n\n')

    cu.add_defn('\n/* Map from PyGccWrapperTypeObject* to GCC tree codes*/\n')
    cu.add_defn('int \n')
    cu.add_defn('gcc_python_tree_type_object_as_tree_code(PyObject *cls, enum tree_code *out)\n')
    cu.add_defn('{\n')
    for tree_type in tree_types:
        cu.add_defn('    if (cls == (PyObject*)&gcc_%sType) {\n'
                    '        *out = %s; return 0;\n'
                    '    }\n'
                    % (tree_type.camel_cased_string(),
                       tree_type.SYM))
    cu.add_defn('    return -1;\n')
    cu.add_defn('}\n')

    cu.add_defn("""
PyGccWrapperTypeObject*
gcc_python_autogenerated_tree_type_for_tree_code(enum tree_code code, int borrow_ref)
{
    PyGccWrapperTypeObject *result;

    assert(code >= 0);
    assert(code < MAX_TREE_CODES);

    result = pytype_for_tree_code[code];

    if (!borrow_ref) {
        Py_INCREF(result);
    }
    return result;
}

PyGccWrapperTypeObject*
gcc_python_autogenerated_tree_type_for_tree(tree t, int borrow_ref)
{
    enum tree_code code = TREE_CODE(t);
    /* printf("code:%i\\n", code); */
    return gcc_python_autogenerated_tree_type_for_tree_code(code, borrow_ref);
}
""")