/* Abstract syntax tree representation.
   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/boot/ast.h"

namespace elna
{
namespace boot
{
    void empty_visitor::visit(variable_declaration *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(constant_definition *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(procedure_definition *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(type_definition *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(procedure_call *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(traits_expression *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(cast_expression *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(assign_statement *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(if_statement *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(while_statement *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(return_statement *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(defer_statement *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(block *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(program *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(binary_expression *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(unary_expression *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(primitive_type_expression *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(array_type_expression *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(pointer_type_expression *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(record_type_expression *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(union_type_expression *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(procedure_type_expression *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(variable_expression *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(array_access_expression *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(field_access_expression *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(dereference_expression *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(number_literal<std::int32_t> *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(number_literal<std::uint32_t> *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(number_literal<double> *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(number_literal<bool> *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(number_literal<unsigned char> *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(number_literal<std::nullptr_t> *)
    {
        __builtin_unreachable();
    }

    void empty_visitor::visit(number_literal<std::string> *)
    {
        __builtin_unreachable();
    }

    node::node(const struct position position)
        : source_position(position)
    {
    }

    const struct position& node::position() const
    {
        return this->source_position;
    }

    statement::statement()
    {
    }

    expression::expression()
    {
    }

    type_expression::type_expression(const struct position position)
        : node(position)
    {
    }

    std::shared_ptr<primitive_type_expression> type_expression::is_primitive()
    {
        return nullptr;
    }

    std::shared_ptr<array_type_expression> type_expression::is_array()
    {
        return nullptr;
    }

    std::shared_ptr<pointer_type_expression> type_expression::is_pointer()
    {
        return nullptr;
    }

    std::shared_ptr<record_type_expression> type_expression::is_record()
    {
        return nullptr;
    }

    std::shared_ptr<union_type_expression> type_expression::is_union()
    {
        return nullptr;
    }

    std::shared_ptr<procedure_type_expression> type_expression::is_procedure()
    {
        return nullptr;
    }

    primitive_type_expression::primitive_type_expression(const struct position position, const std::string& name)
        : type_expression(position), name(name)
    {
    }

    void primitive_type_expression::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    std::shared_ptr<primitive_type_expression> primitive_type_expression::is_primitive()
    {
        return std::static_pointer_cast<primitive_type_expression>(shared_from_this());
    }

    array_type_expression::array_type_expression(const struct position position,
            std::shared_ptr<type_expression> base, const std::uint32_t size)
        : type_expression(position), m_base(base), size(size)
    {
    }

    void array_type_expression::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    std::shared_ptr<array_type_expression> array_type_expression::is_array()
    {
        return std::static_pointer_cast<array_type_expression>(shared_from_this());
    }

    type_expression& array_type_expression::base()
    {
        return *m_base;
    }

    pointer_type_expression::pointer_type_expression(const struct position position,
            std::shared_ptr<type_expression> base)
        : type_expression(position), m_base(base)
    {
    }

    void pointer_type_expression::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    std::shared_ptr<pointer_type_expression> pointer_type_expression::is_pointer()
    {
        return std::static_pointer_cast<pointer_type_expression>(shared_from_this());
    }

    type_expression& pointer_type_expression::base()
    {
        return *m_base;
    }

    record_type_expression::record_type_expression(const struct position position, fields_t&& fields)
        : type_expression(position), fields(std::move(fields))
    {
    }

    void record_type_expression::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    std::shared_ptr<record_type_expression> record_type_expression::is_record()
    {
        return std::static_pointer_cast<record_type_expression>(shared_from_this());
    }

    union_type_expression::union_type_expression(const struct position position, fields_t&& fields)
        : type_expression(position), fields(std::move(fields))
    {
    }

    void union_type_expression::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    std::shared_ptr<union_type_expression> union_type_expression::is_union()
    {
        return std::static_pointer_cast<union_type_expression>(shared_from_this());
    }

    variable_declaration::variable_declaration(const struct position position, const std::string& identifier,
            std::shared_ptr<type_expression> type, const bool exported)
        : definition(position, identifier, exported), m_type(type)
    {
    }

    void variable_declaration::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    type_expression& variable_declaration::variable_type()
    {
        return *m_type;
    }

    definition::definition(const struct position position, const std::string& identifier, const bool exported)
        : node(position), identifier(identifier), exported(exported)
    {
    }

    constant_definition::constant_definition(const struct position position, const std::string& identifier,
            const bool exported, literal *body)
        : definition(position, identifier, exported), m_body(body)
    {
    }

    void constant_definition::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    literal& constant_definition::body()
    {
        return *m_body;
    }

    constant_definition::~constant_definition()
    {
        delete m_body;
    }

    procedure_type_expression::procedure_type_expression(const struct position position,
            std::shared_ptr<type_expression> return_type)
        : type_expression(position), return_type(return_type), no_return(false)
    {
    }

    procedure_type_expression::procedure_type_expression(const struct position position, no_return_t)
        : type_expression(position), return_type(nullptr), no_return(true)
    {
    }

    void procedure_type_expression::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    procedure_type_expression::~procedure_type_expression()
    {
        for (auto parameter : this->parameters)
        {
            delete parameter;
        }
    }

    procedure_definition::procedure_definition(const struct position position, const std::string& identifier,
            const bool exported, std::shared_ptr<procedure_type_expression> heading, block *body)
        : definition(position, identifier, exported), m_heading(heading), body(body)
    {
    }

    void procedure_definition::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    std::shared_ptr<procedure_type_expression> procedure_type_expression::is_procedure()
    {
        return std::static_pointer_cast<procedure_type_expression>(shared_from_this());
    }

    procedure_type_expression& procedure_definition::heading()
    {
        return *m_heading;
    }

    procedure_definition::~procedure_definition()
    {
        delete body;
    }

    type_definition::type_definition(const struct position position, const std::string& identifier,
            const bool exported, std::shared_ptr<type_expression> body)
        : definition(position, identifier, exported), m_body(body)
    {
    }

    void type_definition::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    type_expression& type_definition::body()
    {
        return *m_body;
    }

    block::block(const struct position position)
        : node(position)
    {
    }

    void block::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    block::~block()
    {
        for (statement *body_statement : this->body)
        {
            delete body_statement;
        }
        for (variable_declaration *variable : this->variables)
        {
            delete variable;
        }
        for (constant_definition *constant : this->constants)
        {
            delete constant;
        }
    }

    program::program(const struct position position)
        : block(position)
    {
    }

    void program::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    program::~program()
    {
        for (procedure_definition *procedure : this->procedures)
        {
            delete procedure;
        }
        for (type_definition *type : this->types)
        {
            delete type;
        }
    }

    literal::literal()
    {
    }

    defer_statement::defer_statement(const struct position position)
        : node(position)
    {
    }

    void defer_statement::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    defer_statement::~defer_statement()
    {
        for (statement *body_statement : statements)
        {
            delete body_statement;
        }
    }

    designator_expression::designator_expression()
    {
    }

    variable_expression::variable_expression(const struct position position, const std::string& name)
        : node(position), name(name)
    {
    }

    void variable_expression::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    variable_expression *variable_expression::is_variable()
    {
        return this;
    }

    array_access_expression::array_access_expression(const struct position position,
            expression *base, expression *index)
        : node(position), m_base(base), m_index(index)
    {
    }

    void array_access_expression::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    expression& array_access_expression::index()
    {
        return *m_index;
    }

    expression& array_access_expression::base()
    {
        return *m_base;
    }

    array_access_expression *array_access_expression::is_array_access()
    {
        return this;
    }

    array_access_expression::~array_access_expression()
    {
        delete m_index;
        delete m_base;
    }

    field_access_expression::field_access_expression(const struct position position,
            expression *base, const std::string& field)
        : node(position), m_base(base), m_field(field)
    {
    }

    void field_access_expression::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    expression& field_access_expression::base()
    {
        return *m_base;
    }

    std::string& field_access_expression::field()
    {
        return m_field;
    }

    field_access_expression *field_access_expression::is_field_access()
    {
        return this;
    }

    field_access_expression::~field_access_expression()
    {
        delete m_base;
    }

    dereference_expression::dereference_expression(const struct position position,
            expression *base)
        : node(position), m_base(base)
    {
    }

    void dereference_expression::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    expression& dereference_expression::base()
    {
        return *m_base;
    }

    dereference_expression *dereference_expression::is_dereference()
    {
        return this;
    }

    dereference_expression::~dereference_expression()
    {
        delete m_base;
    }

    binary_expression::binary_expression(const struct position position, expression *lhs,
            expression *rhs, const binary_operator operation)
        : node(position), m_lhs(lhs), m_rhs(rhs), m_operator(operation)
    {
    }

    void binary_expression::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    expression& binary_expression::lhs()
    {
        return *m_lhs;
    }

    expression& binary_expression::rhs()
    {
        return *m_rhs;
    }

    binary_operator binary_expression::operation() const
    {
        return m_operator;
    }

    binary_expression::~binary_expression()
    {
        delete m_lhs;
        delete m_rhs;
    }

    unary_expression::unary_expression(const struct position position, expression *operand,
            const unary_operator operation)
        : node(position), m_operand(std::move(operand)), m_operator(operation)
    {
    }

    void unary_expression::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    expression& unary_expression::operand()
    {
        return *m_operand;
    }

    unary_operator unary_expression::operation() const
    {
        return this->m_operator;
    }

    unary_expression::~unary_expression()
    {
        delete m_operand;
    }

    procedure_call::procedure_call(const struct position position, designator_expression *callable)
        : node(position), m_callable(callable)
    {
    }

    void procedure_call::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    designator_expression& procedure_call::callable()
    {
        return *m_callable;
    }

    procedure_call::~procedure_call()
    {
        for (expression *const argument : arguments)
        {
            delete argument;
        }
        delete m_callable;
    }

    cast_expression::cast_expression(const struct position position,
            std::shared_ptr<type_expression> target, expression *value)
        : node(position), m_target(target), m_value(value)
    {
    }

    void cast_expression::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    type_expression& cast_expression::target()
    {
        return *m_target;
    }

    expression& cast_expression::value()
    {
        return *m_value;
    }

    cast_expression::~cast_expression()
    {
        delete m_value;
    }

    traits_expression::traits_expression(const struct position position,
            const std::string& name, std::shared_ptr<type_expression> type)
        : node(position), m_type(type), name(name)
    {
    }

    void traits_expression::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    type_expression& traits_expression::type()
    {
        return *m_type;
    }

    conditional_statements::conditional_statements(expression *prerequisite)
        : m_prerequisite(prerequisite)
    {
    }

    expression& conditional_statements::prerequisite()
    {
        return *m_prerequisite;
    }

    conditional_statements::~conditional_statements()
    {
        delete m_prerequisite;
        for (auto statement : statements)
        {
            delete statement;
        }
    }

    return_statement::return_statement(const struct position position, expression *return_expression)
        : node(position), m_return_expression(return_expression)
    {
    }

    void return_statement::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    expression *return_statement::return_expression()
    {
        return m_return_expression;
    }

    return_statement::~return_statement()
    {
        delete m_return_expression;
    }

    void assign_statement::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    assign_statement::assign_statement(const struct position position, designator_expression *lvalue,
            expression *rvalue)
        : node(position), m_lvalue(lvalue), m_rvalue(rvalue)
    {
    }

    variable_expression *designator_expression::is_variable()
    {
        return nullptr;
    }

    array_access_expression *designator_expression::is_array_access()
    {
        return nullptr;
    }

    field_access_expression *designator_expression::is_field_access()
    {
        return nullptr;
    }

    dereference_expression *designator_expression::is_dereference()
    {
        return nullptr;
    }

    designator_expression& assign_statement::lvalue()
    {
        return *m_lvalue;
    }

    expression& assign_statement::rvalue()
    {
        return *m_rvalue;
    }

    assign_statement::~assign_statement()
    {
        delete m_rvalue;
    }

    if_statement::if_statement(const struct position position, conditional_statements *body,
            std::vector<statement *> *alternative)
        : node(position), m_body(body), m_alternative(alternative)
    {
    }

    void if_statement::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    conditional_statements& if_statement::body()
    {
        return *m_body;
    }

    std::vector<statement *> *if_statement::alternative()
    {
        return m_alternative;
    }

    if_statement::~if_statement()
    {
        delete m_body;
        for (const auto branch : branches)
        {
            delete branch;
        }
        delete m_alternative;
    }

    while_statement::while_statement(const struct position position, conditional_statements *body)
        : node(position), m_body(body)
    {
    }

    void while_statement::accept(parser_visitor *visitor)
    {
        visitor->visit(this);
    }

    conditional_statements& while_statement::body()
    {
        return *m_body;
    }

    while_statement::~while_statement()
    {
        delete m_body;
        for (const auto branch : branches)
        {
            delete branch;
        }
    }

    const char *print_binary_operator(const binary_operator operation)
    {
        switch (operation)
        {
            case binary_operator::sum:
                return "+";
            case binary_operator::subtraction: 
                return "-";
            case binary_operator::multiplication:
                return "*";
            case binary_operator::division:
                return "/";
            case binary_operator::remainder:
                return "%";
            case binary_operator::equals:
                return "=";
            case binary_operator::not_equals:
                return "<>";
            case binary_operator::less:
                return "<";
            case binary_operator::less_equal:
                return "<=";
            case binary_operator::greater:
                return ">";
            case binary_operator::greater_equal:
                return ">=";
            case binary_operator::conjunction:
                return "and";
            case binary_operator::disjunction:
                return "or";
            case binary_operator::exclusive_disjunction:
                return "xor";
            case binary_operator::shift_left:
                return "<<";
            case binary_operator::shift_right:
                return ">>";
        }
        __builtin_unreachable();
    };
}
}