/* Elna frontend specific diagnostic routines.
   Copyright (C) 2025 Free Software Foundation, Inc.

GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "elna/gcc/elna-diagnostic.h"
#include "elna/gcc/elna-tree.h"
#include "elna/gcc/elna1.h"

namespace elna
{
namespace gcc
{
    location_t get_location(const boot::position *position)
    {
        linemap_line_start(line_table, position->line, 0);

        return linemap_position_for_column(line_table, position->column);
    }

    std::string print_aggregate_name(tree type, const std::string& kind_name)
    {
        if (TYPE_IDENTIFIER(type) == NULL_TREE)
        {
            return kind_name;
        }
        else
        {
            return std::string(IDENTIFIER_POINTER(TYPE_IDENTIFIER(type)));
        }
    }

    std::string print_type(tree type)
    {
        gcc_assert(TYPE_P(type));

        if (type == elna_int_type_node)
        {
            return "Int";
        }
        else if (type == elna_word_type_node)
        {
            return "Word";
        }
        else if (type == elna_bool_type_node)
        {
            return "Bool";
        }
        else if (type == elna_byte_type_node)
        {
            return "Byte";
        }
        else if (type == elna_float_type_node)
        {
            return "Float";
        }
        else if (type == elna_char_type_node)
        {
            return "Char";
        }
        else if (type == elna_string_type_node)
        {
            return "String";
        }
        else if (is_void_type(type)) // For procedures without a return type.
        {
            return "()";
        }
        else if (is_pointer_type(type))
        {
            tree pointer_target_type = TREE_TYPE(type);

            if (TREE_CODE(pointer_target_type) == FUNCTION_TYPE)
            {
                return print_type(pointer_target_type);
            }
            else
            {
                return std::string("^" + print_type(pointer_target_type));
            }
        }
        else if (TREE_CODE(type) == FUNCTION_TYPE)
        {
            std::string output = "proc(";
            tree parameter_type = TYPE_ARG_TYPES(type);
            while (TREE_VALUE(parameter_type) != void_type_node)
            {
                output += print_type(TREE_VALUE(parameter_type));
                parameter_type = TREE_CHAIN(parameter_type);
                if (TREE_VALUE(parameter_type) == void_type_node)
                {
                    break;
                }
                else
                {
                    output += ", ";
                }
            }
            output += ')';
            if (!is_void_type(TREE_TYPE(type)))
            {
                output += " -> " + print_type(TREE_TYPE(type));
            }
            return output;
        }
        else if (is_array_type(type))
        {
            return "array";
        }
        else if (TREE_CODE(type) == RECORD_TYPE)
        {
            return print_aggregate_name(type, "record");
        }
        else if (TREE_CODE(type) == UNION_TYPE)
        {
            return print_aggregate_name(type, "union");
        }
        else
        {
            return "<<unknown-type>>";
        }
        gcc_unreachable();
    }
}
}