elna/gcc/elna-generic.cc

1173 lines
46 KiB
C++
Raw Normal View History

/* Visitor generating a GENERIC tree.
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/>. */
2025-02-01 11:47:23 +01:00
#include <array>
2024-12-27 23:38:25 +01:00
#include "elna/gcc/elna-generic.h"
#include "elna/gcc/elna-diagnostic.h"
2025-02-11 01:37:55 +01:00
#include "elna/gcc/elna1.h"
2024-12-23 13:54:11 +01:00
2025-02-11 01:37:55 +01:00
#include "ggc.h"
#include "function.h"
2024-12-23 13:54:11 +01:00
#include "cgraph.h"
#include "gimplify.h"
2024-12-27 23:38:25 +01:00
#include "stringpool.h"
#include "diagnostic.h"
2024-12-31 18:10:34 +01:00
#include "realmpfr.h"
2025-01-09 22:40:39 +01:00
#include "stor-layout.h"
2025-01-11 13:32:37 +01:00
#include "varasm.h"
2025-01-30 23:09:51 +01:00
#include "fold-const.h"
2025-02-12 00:56:21 +01:00
#include "langhooks.h"
2025-01-09 22:40:39 +01:00
#include <set>
2024-12-23 13:54:11 +01:00
namespace elna
{
namespace gcc
{
2025-02-17 19:36:25 +01:00
generic_visitor::generic_visitor(std::shared_ptr<symbol_table> symbol_table)
{
this->symbol_map = symbol_table;
}
2025-02-14 08:05:03 +01:00
void generic_visitor::build_procedure_call(location_t call_location,
tree symbol, const std::vector<boot::expression *>& arguments)
{
vec<tree, va_gc> *argument_trees = nullptr;
tree current_parameter = TYPE_ARG_TYPES(TREE_TYPE(symbol));
vec_alloc(argument_trees, arguments.size());
for (boot::expression *const argument : arguments)
{
location_t argument_location = get_location(&argument->position());
if (is_void_type(TREE_VALUE(current_parameter)))
{
error_at(argument_location, "too many arguments, expected %i, got %lu",
list_length(TYPE_ARG_TYPES(TREE_TYPE(symbol))) - 1, arguments.size());
this->current_expression = error_mark_node;
break;
}
argument->accept(this);
if (!is_assignable_from(TREE_VALUE(current_parameter), this->current_expression))
{
error_at(argument_location,
"cannot assign value of type '%s' to variable of type '%s'",
print_type(TREE_TYPE(this->current_expression)).c_str(),
print_type(TREE_VALUE(current_parameter)).c_str());
this->current_expression = error_mark_node;
}
current_parameter = TREE_CHAIN(current_parameter);
argument_trees->quick_push(this->current_expression);
}
tree stmt = build_call_expr_loc_vec(call_location, symbol, argument_trees);
if (!is_void_type(TREE_VALUE(current_parameter)))
{
error_at(call_location, "too few arguments, expected %i, got %lu",
list_length(TYPE_ARG_TYPES(TREE_TYPE(symbol))) - 1, arguments.size());
this->current_expression = error_mark_node;
}
else if (TREE_TYPE(TREE_TYPE(symbol)) == void_type_node)
{
append_statement(stmt);
this->current_expression = NULL_TREE;
}
else
{
this->current_expression = stmt;
}
}
void generic_visitor::build_record_call(location_t call_location,
tree symbol, const std::vector<boot::expression *>& arguments)
{
vec<constructor_elt, va_gc> *tree_arguments = nullptr;
tree record_fields = TYPE_FIELDS(symbol);
for (boot::expression *const argument : arguments)
{
location_t argument_location = get_location(&argument->position());
if (is_void_type(record_fields))
{
error_at(argument_location, "too many arguments, expected %i, got %lu",
list_length(TYPE_FIELDS(symbol)), arguments.size());
this->current_expression = error_mark_node;
break;
}
argument->accept(this);
tree unqualified_field = get_qualified_type(TREE_TYPE(record_fields), TYPE_UNQUALIFIED);
if (!is_assignable_from(unqualified_field, this->current_expression))
2025-02-14 08:05:03 +01:00
{
error_at(argument_location,
"cannot assign value of type '%s' to variable of type '%s'",
print_type(TREE_TYPE(this->current_expression)).c_str(),
print_type(TREE_TYPE(record_fields)).c_str());
this->current_expression = error_mark_node;
}
CONSTRUCTOR_APPEND_ELT(tree_arguments, record_fields, this->current_expression);
record_fields = TREE_CHAIN(record_fields);
}
if (!is_void_type(record_fields))
{
error_at(call_location, "too few arguments, expected %i, got %lu",
list_length(TYPE_FIELDS(symbol)), arguments.size());
this->current_expression = error_mark_node;
}
else
{
this->current_expression = build_constructor(symbol, tree_arguments);
}
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::call_expression *expression)
2024-12-23 13:54:11 +01:00
{
2025-02-11 01:37:55 +01:00
tree symbol = this->lookup(expression->name());
2025-02-12 20:47:47 +01:00
location_t call_location = get_location(&expression->position());
2024-12-23 13:54:11 +01:00
2025-02-04 13:28:09 +01:00
if (symbol == NULL_TREE)
{
2025-02-12 20:47:47 +01:00
error_at(call_location, "procedure '%s' not declared",
2025-01-28 11:21:02 +01:00
expression->name().c_str());
this->current_expression = error_mark_node;
2025-02-04 13:28:09 +01:00
}
2025-02-12 20:47:47 +01:00
else if (DECL_P(symbol) && is_procedure_type(TREE_TYPE(symbol)))
2025-02-04 13:28:09 +01:00
{
2025-02-14 08:05:03 +01:00
build_procedure_call(call_location, symbol, expression->arguments());
2025-02-04 13:28:09 +01:00
}
2025-02-14 08:05:03 +01:00
else if (TYPE_P(symbol) && TREE_CODE(symbol) == RECORD_TYPE)
2025-02-13 22:54:47 +01:00
{
2025-02-14 08:05:03 +01:00
build_record_call(call_location, symbol, expression->arguments());
2025-02-13 22:54:47 +01:00
}
2025-02-04 13:28:09 +01:00
else
{
2025-02-12 20:47:47 +01:00
error_at(call_location, "'%s' cannot be called, it is neither a procedure nor record",
print_type(TYPE_P(symbol) ? symbol : TREE_TYPE(symbol)).c_str());
this->current_expression = error_mark_node;
2025-01-11 13:32:37 +01:00
}
2024-12-23 13:54:11 +01:00
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::cast_expression *expression)
2025-01-28 11:21:02 +01:00
{
tree cast_target = build_type(expression->target());
gcc_assert(cast_target != NULL_TREE);
expression->value().accept(this);
this->current_expression = build1_loc(get_location(&expression->position()), CONVERT_EXPR,
cast_target, this->current_expression);
}
2025-02-14 08:05:03 +01:00
void generic_visitor::visit(boot::type_expression *expression)
2025-01-29 12:55:52 +01:00
{
2025-02-14 08:05:03 +01:00
this->current_expression = build_type(expression->body());
2025-01-31 09:46:17 +01:00
}
void generic_visitor::visit(boot::program *program)
2024-12-23 13:54:11 +01:00
{
for (boot::constant_definition *const constant : program->constants)
2025-01-22 20:19:26 +01:00
{
constant->accept(this);
2025-01-22 20:19:26 +01:00
}
for (boot::type_definition *const type : program->types)
2025-01-11 13:32:37 +01:00
{
type->accept(this);
2025-01-11 13:32:37 +01:00
}
for (boot::variable_declaration *const variable : program->variables)
{
variable->accept(this);
}
for (boot::procedure_definition *const procedure : program->procedures)
{
procedure->accept(this);
}
2025-02-12 00:56:21 +01:00
tree declaration_type = build_function_type_list(integer_type_node, integer_type_node,
build_pointer_type(build_pointer_type(char_type_node)), NULL_TREE);
tree fndecl = build_fn_decl("main", declaration_type);
2025-02-11 01:37:55 +01:00
2024-12-23 13:54:11 +01:00
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node);
DECL_CONTEXT(resdecl) = fndecl;
DECL_RESULT(fndecl) = resdecl;
2025-01-15 01:48:09 +01:00
2025-02-11 01:37:55 +01:00
push_struct_function(fndecl, false);
DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc<language_function>();
2025-01-04 20:24:34 +01:00
enter_scope();
2024-12-23 13:54:11 +01:00
2025-02-12 00:56:21 +01:00
tree parameter_type = TYPE_ARG_TYPES(declaration_type);
for (const char *argument_name : std::array<const char *, 2>{ "count", "parameters" })
2025-02-01 11:47:23 +01:00
{
2025-02-12 00:56:21 +01:00
tree declaration_tree = build_decl(UNKNOWN_LOCATION, PARM_DECL,
get_identifier(argument_name), TREE_VALUE(parameter_type));
DECL_CONTEXT(declaration_tree) = fndecl;
DECL_ARG_TYPE(declaration_tree) = TREE_VALUE(parameter_type);
2025-02-11 01:37:55 +01:00
2025-02-12 00:56:21 +01:00
this->symbol_map->enter(argument_name, declaration_tree);
DECL_ARGUMENTS(fndecl) = chainon(DECL_ARGUMENTS(fndecl), declaration_tree);
parameter_type = TREE_CHAIN(parameter_type);
2025-02-01 11:47:23 +01:00
}
for (boot::statement *const body_statement : program->body)
2025-01-16 15:09:58 +01:00
{
body_statement->accept(this);
}
tree set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(fndecl),
2025-01-18 21:30:11 +01:00
build_int_cst_type(integer_type_node, 0));
tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result);
2025-02-12 00:56:21 +01:00
append_statement(return_stmt);
tree mapping = leave_scope();
2025-01-15 01:48:09 +01:00
2025-02-12 00:56:21 +01:00
BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl;
DECL_INITIAL(fndecl) = BIND_EXPR_BLOCK(mapping);
DECL_SAVED_TREE(fndecl) = mapping;
2025-01-15 01:48:09 +01:00
DECL_EXTERNAL(fndecl) = 0;
DECL_PRESERVE_P(fndecl) = 1;
2025-01-15 01:48:09 +01:00
2025-02-11 01:37:55 +01:00
pop_cfun();
gimplify_function_tree(fndecl);
cgraph_node::finalize_function(fndecl, true);
2024-12-23 13:54:11 +01:00
}
2024-12-27 10:51:46 +01:00
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::procedure_definition *definition)
2025-01-11 13:32:37 +01:00
{
2025-01-16 15:09:58 +01:00
std::vector<tree> parameter_types(definition->parameters.size());
2025-01-11 13:32:37 +01:00
2025-01-16 15:09:58 +01:00
for (std::size_t i = 0; i < definition->parameters.size(); ++i)
2025-01-11 13:32:37 +01:00
{
2025-02-14 08:05:03 +01:00
parameter_types[i] = build_type(definition->parameters.at(i)->variable_type());
2025-01-11 13:32:37 +01:00
}
2025-01-18 21:30:11 +01:00
tree return_type = definition->return_type() == nullptr
? void_type_node
: build_type(*definition->return_type());
tree declaration_type = build_function_type_array(return_type,
2025-01-16 15:09:58 +01:00
definition->parameters.size(), parameter_types.data());
tree fndecl = build_fn_decl(definition->identifier.c_str(), declaration_type);
this->symbol_map->enter(definition->identifier, fndecl);
if (definition->no_return)
{
TREE_THIS_VOLATILE(fndecl) = 1;
}
2025-01-16 15:09:58 +01:00
if (definition->body() != nullptr)
{
2025-01-18 21:30:11 +01:00
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, return_type);
DECL_CONTEXT(resdecl) = fndecl;
DECL_RESULT(fndecl) = resdecl;
2025-01-15 01:48:09 +01:00
2025-02-12 00:56:21 +01:00
push_struct_function(fndecl, false);
DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc<language_function>();
2025-01-16 15:09:58 +01:00
enter_scope();
}
2025-02-12 00:56:21 +01:00
tree argument_chain = NULL_TREE;
2025-01-16 15:09:58 +01:00
for (std::size_t i = 0; i < definition->parameters.size(); ++i)
2025-01-15 01:48:09 +01:00
{
2025-01-16 15:09:58 +01:00
auto parameter = definition->parameters.at(i);
2025-01-15 01:48:09 +01:00
tree declaration_tree = build_decl(get_location(&parameter->position()), PARM_DECL,
2025-02-07 22:12:59 +01:00
get_identifier(parameter->identifier.c_str()), parameter_types[i]);
DECL_CONTEXT(declaration_tree) = fndecl;
2025-01-15 01:48:09 +01:00
DECL_ARG_TYPE(declaration_tree) = parameter_types[i];
2025-01-16 15:09:58 +01:00
if (definition->body() != nullptr)
{
2025-02-07 22:12:59 +01:00
this->symbol_map->enter(parameter->identifier, declaration_tree);
2025-01-16 15:09:58 +01:00
}
2025-02-12 00:56:21 +01:00
argument_chain = chainon(argument_chain, declaration_tree);
2025-01-15 01:48:09 +01:00
}
2025-02-12 00:56:21 +01:00
DECL_ARGUMENTS(fndecl) = argument_chain;
TREE_PUBLIC(fndecl) = definition->exported;
2025-01-11 13:32:37 +01:00
2025-01-16 15:09:58 +01:00
if (definition->body() != nullptr)
{
definition->body()->accept(this);
2025-02-12 00:56:21 +01:00
tree mapping = leave_scope();
2025-01-11 13:32:37 +01:00
2025-02-12 00:56:21 +01:00
BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl;
DECL_INITIAL(fndecl) = BIND_EXPR_BLOCK(mapping);
DECL_SAVED_TREE(fndecl) = mapping;
2025-01-11 13:32:37 +01:00
DECL_EXTERNAL(fndecl) = 0;
DECL_PRESERVE_P(fndecl) = 1;
2025-01-11 13:32:37 +01:00
2025-02-12 00:56:21 +01:00
pop_cfun();
gimplify_function_tree(fndecl);
cgraph_node::finalize_function(fndecl, true);
2025-01-16 15:09:58 +01:00
}
else
{
DECL_EXTERNAL(fndecl) = 1;
2025-01-16 15:09:58 +01:00
}
2025-01-11 13:32:37 +01:00
}
2025-01-04 20:24:34 +01:00
void generic_visitor::enter_scope()
{
2025-02-17 19:36:25 +01:00
this->symbol_map = std::make_shared<symbol_table>(this->symbol_map);
2025-02-12 00:56:21 +01:00
// Chain the binding levels.
struct binding_level *new_level = ggc_cleared_alloc<binding_level>();
new_level->level_chain = f_binding_level;
new_level->statement_list = alloc_stmt_list();
f_binding_level = new_level;
2025-01-04 20:24:34 +01:00
}
2025-02-12 00:56:21 +01:00
tree generic_visitor::leave_scope()
2025-01-04 20:24:34 +01:00
{
2025-02-12 00:56:21 +01:00
// Variables are only defined in the top function scope.
tree variables = f_binding_level->level_chain == nullptr ? f_names : NULL_TREE;
tree new_block = build_block(variables, f_binding_level->blocks, NULL_TREE, NULL_TREE);
2025-02-07 22:12:59 +01:00
2025-02-12 00:56:21 +01:00
for (tree it = f_binding_level->blocks; it != NULL_TREE; it = BLOCK_CHAIN(it))
2025-02-07 22:12:59 +01:00
{
BLOCK_SUPERCONTEXT(it) = new_block;
}
2025-02-12 00:56:21 +01:00
tree bind_expr = build3(BIND_EXPR, void_type_node, variables, chain_defer(), new_block);
this->symbol_map = this->symbol_map->scope();
2025-01-04 20:24:34 +01:00
2025-02-12 00:56:21 +01:00
f_binding_level = f_binding_level->level_chain;
2025-02-07 22:12:59 +01:00
2025-02-12 00:56:21 +01:00
if (f_binding_level != nullptr)
2025-02-07 22:12:59 +01:00
{
2025-02-12 00:56:21 +01:00
f_binding_level->blocks = chainon(f_binding_level->blocks, new_block);
2025-02-07 22:12:59 +01:00
}
2025-02-12 00:56:21 +01:00
return bind_expr;
2025-01-04 20:24:34 +01:00
}
2025-02-11 01:37:55 +01:00
tree generic_visitor::lookup(const std::string& name)
2024-12-27 10:51:46 +01:00
{
2025-02-11 01:37:55 +01:00
if (name == "Int")
{
return elna_int_type_node;
}
if (name == "Word")
{
return elna_word_type_node;
}
if (name == "Char")
{
return elna_char_type_node;
}
if (name == "Bool")
{
return elna_bool_type_node;
}
if (name == "Byte")
{
return elna_byte_type_node;
}
if (name == "Float")
{
return elna_float_type_node;
}
if (name == "String")
{
return elna_string_type_node;
}
return this->symbol_map->lookup(name);
}
2025-01-31 09:46:17 +01:00
2025-02-11 01:37:55 +01:00
void generic_visitor::visit(boot::number_literal<std::int32_t> *literal)
{
2025-02-14 08:05:03 +01:00
this->current_expression = build_int_cst(elna_int_type_node, literal->value);
2025-01-24 11:41:14 +01:00
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::number_literal<std::uint32_t> *literal)
2025-01-24 11:41:14 +01:00
{
2025-02-14 08:05:03 +01:00
this->current_expression = build_int_cstu(elna_word_type_node, literal->value);
2024-12-27 10:51:46 +01:00
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::number_literal<double> *literal)
2024-12-31 18:10:34 +01:00
{
REAL_VALUE_TYPE real_value1;
mpfr_t number;
mpfr_init2(number, SIGNIFICAND_BITS);
2025-02-14 08:05:03 +01:00
mpfr_set_d(number, literal->value, MPFR_RNDN);
2024-12-31 18:10:34 +01:00
real_from_mpfr(&real_value1, number, double_type_node, MPFR_RNDN);
this->current_expression = build_real(double_type_node, real_value1);
mpfr_clear(number);
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::number_literal<bool> *boolean)
2024-12-27 23:38:25 +01:00
{
2025-02-14 08:05:03 +01:00
this->current_expression = boolean->value ? boolean_true_node : boolean_false_node;
2025-01-01 23:02:19 +01:00
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::number_literal<unsigned char> *character)
2025-01-01 23:02:19 +01:00
{
2025-02-14 08:05:03 +01:00
this->current_expression = build_int_cstu(elna_char_type_node, character->value);
2024-12-27 23:38:25 +01:00
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::number_literal<nullptr_t> *)
2025-01-30 01:03:16 +01:00
{
2025-02-12 13:32:59 +01:00
this->current_expression = elna_pointer_nil_node;
2025-01-30 01:03:16 +01:00
}
2025-02-07 22:12:59 +01:00
void generic_visitor::visit(boot::number_literal<std::string> *string)
2025-01-03 22:18:35 +01:00
{
2025-02-14 08:05:03 +01:00
tree index_constant = build_int_cstu(elna_word_type_node, string->value.size());
2025-02-11 01:37:55 +01:00
tree string_type = build_array_type(elna_char_type_node, build_index_type(index_constant));
2025-02-07 22:12:59 +01:00
2025-02-14 08:05:03 +01:00
tree string_literal = build_string(string->value.size(), string->value.c_str());
2025-02-07 22:12:59 +01:00
TREE_TYPE(string_literal) = string_type;
TREE_CONSTANT(string_literal) = 1;
TREE_READONLY(string_literal) = 1;
TREE_STATIC(string_literal) = 1;
2025-02-12 20:47:47 +01:00
string_type = TREE_TYPE(elna_string_ptr_field_node);
2025-02-11 01:37:55 +01:00
string_literal = build4(ARRAY_REF, elna_char_type_node,
string_literal, integer_zero_node, NULL_TREE, NULL_TREE);
2025-02-07 22:12:59 +01:00
string_literal = build1(ADDR_EXPR, string_type, string_literal);
2025-02-13 22:54:47 +01:00
vec<constructor_elt, va_gc> *elms = nullptr;
2025-02-12 20:47:47 +01:00
CONSTRUCTOR_APPEND_ELT(elms, elna_string_ptr_field_node, string_literal);
CONSTRUCTOR_APPEND_ELT(elms, elna_string_length_field_node, index_constant);
2025-02-07 22:12:59 +01:00
2025-02-11 01:37:55 +01:00
this->current_expression = build_constructor(elna_string_type_node, elms);
2025-01-03 22:18:35 +01:00
}
tree generic_visitor::build_arithmetic_operation(boot::binary_expression *expression,
tree_code operator_code, tree left, tree right)
2025-01-13 11:55:19 +01:00
{
return build_binary_operation(is_numeric_type(TREE_TYPE(left)),
expression, operator_code, left, right, TREE_TYPE(left));
}
2025-01-13 11:55:19 +01:00
tree generic_visitor::build_comparison_operation(boot::binary_expression *expression,
tree_code operator_code, tree left, tree right)
{
return build_binary_operation(is_numeric_type(TREE_TYPE(left)) || is_pointer_type(TREE_TYPE(left)),
2025-02-11 01:37:55 +01:00
expression, operator_code, left, right, elna_bool_type_node);
}
2025-02-14 08:05:03 +01:00
tree generic_visitor::build_bit_logic_operation(boot::binary_expression *expression, tree left, tree right)
{
2025-02-14 08:05:03 +01:00
location_t expression_location = get_location(&expression->position());
tree left_type = TREE_TYPE(left);
tree right_type = TREE_TYPE(right);
tree_code logical_code, bit_code;
if (expression->operation() == boot::binary_operator::conjunction)
{
bit_code = BIT_AND_EXPR;
logical_code = TRUTH_ANDIF_EXPR;
}
else if (expression->operation() == boot::binary_operator::disjunction)
{
bit_code = BIT_IOR_EXPR;
logical_code = TRUTH_ORIF_EXPR;
}
else if (expression->operation() == boot::binary_operator::exclusive_disjunction)
{
bit_code = BIT_XOR_EXPR;
logical_code = TRUTH_XOR_EXPR;
}
else
{
gcc_unreachable();
}
if (left_type == elna_bool_type_node)
{
return build2_loc(expression_location, logical_code, elna_bool_type_node, left, right);
}
else if (is_integral_type(left_type))
{
return build2_loc(expression_location, bit_code, left_type, left, right);
}
else
{
error_at(expression_location,
"invalid operands of type '%s' and '%s' for operator %s",
print_type(left_type).c_str(), print_type(right_type).c_str(),
elna::boot::print_binary_operator(expression->operation()));
return error_mark_node;
}
}
2025-02-12 00:56:21 +01:00
tree generic_visitor::build_equality_operation(boot::binary_expression *expression, tree left, tree right)
{
2025-02-12 00:56:21 +01:00
location_t expression_location = get_location(&expression->position());
tree_code equality_code, combination_code;
if (expression->operation() == boot::binary_operator::equals)
{
equality_code = EQ_EXPR;
combination_code = TRUTH_ANDIF_EXPR;
}
else if (expression->operation() == boot::binary_operator::not_equals)
{
equality_code = NE_EXPR;
combination_code = TRUTH_ORIF_EXPR;
}
else
{
gcc_unreachable();
}
if (TREE_TYPE(left) == elna_string_type_node)
{
2025-02-12 20:47:47 +01:00
tree lhs_length = build3(COMPONENT_REF, TREE_TYPE(elna_string_length_field_node),
left, elna_string_length_field_node, NULL_TREE);
tree lhs_ptr = build3(COMPONENT_REF, TREE_TYPE(elna_string_ptr_field_node),
left, elna_string_ptr_field_node, NULL_TREE);
2025-02-12 00:56:21 +01:00
2025-02-12 20:47:47 +01:00
tree rhs_length = build3(COMPONENT_REF, TREE_TYPE(elna_string_length_field_node),
right, elna_string_length_field_node, NULL_TREE);
tree rhs_ptr = build3(COMPONENT_REF, TREE_TYPE(elna_string_ptr_field_node),
right, elna_string_ptr_field_node, NULL_TREE);
2025-02-12 00:56:21 +01:00
tree length_equality = build2(equality_code, elna_bool_type_node, lhs_length, rhs_length);
tree *memcmp = elna_global_decls->get("__builtin_memcmp");
gcc_assert(memcmp != nullptr);
tree fndecl_type = build_function_type(integer_type_node, TYPE_ARG_TYPES(*memcmp));
tree memcmp_addr = build1(ADDR_EXPR, build_pointer_type(fndecl_type), *memcmp);
tree memcmp_call = build_call_nary(integer_type_node, memcmp_addr, 3, lhs_ptr, rhs_ptr, lhs_length);
tree equals_zero = build2(equality_code, elna_bool_type_node, memcmp_call, integer_zero_node);
return build2(combination_code, elna_bool_type_node, length_equality, equals_zero);
}
else
{
return build2_loc(expression_location, equality_code, elna_bool_type_node, left, right);
}
2025-01-13 11:55:19 +01:00
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::binary_expression *expression)
2024-12-27 10:51:46 +01:00
{
expression->lhs().accept(this);
tree left = this->current_expression;
tree left_type = get_qualified_type(TREE_TYPE(left), TYPE_UNQUALIFIED);
2024-12-27 10:51:46 +01:00
expression->rhs().accept(this);
tree right = this->current_expression;
tree right_type = get_qualified_type(TREE_TYPE(right), TYPE_UNQUALIFIED);
2024-12-27 10:51:46 +01:00
location_t expression_location = get_location(&expression->position());
2024-12-27 10:51:46 +01:00
if ((is_pointer_type(left_type) || is_pointer_type(right_type))
&& (expression->operation() == boot::binary_operator::sum
|| expression->operation() == boot::binary_operator::subtraction))
{
this->current_expression = do_pointer_arithmetic(expression->operation(), left, right);
if (this->current_expression == error_mark_node)
{
error_at(expression_location,
"invalid operation %s on a pointer and an integral type",
boot::print_binary_operator(expression->operation()));
}
else if (TREE_TYPE(this->current_expression) == ssizetype)
{
2025-02-11 01:37:55 +01:00
this->current_expression = fold_convert(elna_int_type_node, this->current_expression);
}
return;
}
2025-02-14 08:05:03 +01:00
if (left_type != right_type
&& !are_compatible_pointers(left_type, right)
2025-02-15 00:38:46 +01:00
&& !are_compatible_pointers(right_type, left)
&& !(is_integral_type(left_type) && right_type == elna_word_type_node))
2024-12-31 18:10:34 +01:00
{
error_at(expression_location,
2025-02-15 00:38:46 +01:00
"invalid operands of type '%s' and '%s' for operator %s",
print_type(left_type).c_str(), print_type(right_type).c_str(),
2025-01-31 09:46:17 +01:00
boot::print_binary_operator(expression->operation()));
2024-12-31 18:10:34 +01:00
this->current_expression = error_mark_node;
return;
}
2024-12-27 10:51:46 +01:00
switch (expression->operation())
{
2025-01-31 09:46:17 +01:00
case boot::binary_operator::sum:
this->current_expression = build_arithmetic_operation(expression, PLUS_EXPR, left, right);
2024-12-27 10:51:46 +01:00
break;
2025-01-31 09:46:17 +01:00
case boot::binary_operator::subtraction:
this->current_expression = build_arithmetic_operation(expression, MINUS_EXPR, left, right);
2024-12-27 10:51:46 +01:00
break;
2025-01-31 09:46:17 +01:00
case boot::binary_operator::division:
this->current_expression = build_arithmetic_operation(expression, TRUNC_DIV_EXPR, left, right);
2024-12-27 10:51:46 +01:00
break;
2025-01-31 09:46:17 +01:00
case boot::binary_operator::remainder:
this->current_expression = build_arithmetic_operation(expression, TRUNC_MOD_EXPR, left, right);
2025-01-25 19:50:36 +01:00
break;
2025-01-31 09:46:17 +01:00
case boot::binary_operator::multiplication:
this->current_expression = build_arithmetic_operation(expression, MULT_EXPR, left, right);
2024-12-27 10:51:46 +01:00
break;
2025-01-31 09:46:17 +01:00
case boot::binary_operator::less:
this->current_expression = build_comparison_operation(expression, LT_EXPR, left, right);
2025-01-13 11:55:19 +01:00
break;
2025-01-31 09:46:17 +01:00
case boot::binary_operator::greater:
this->current_expression = build_comparison_operation(expression, GT_EXPR, left, right);
2025-01-13 11:55:19 +01:00
break;
2025-01-31 09:46:17 +01:00
case boot::binary_operator::less_equal:
this->current_expression = build_comparison_operation(expression, LE_EXPR, left, right);
2025-01-13 11:55:19 +01:00
break;
2025-01-31 09:46:17 +01:00
case boot::binary_operator::greater_equal:
this->current_expression = build_comparison_operation(expression, GE_EXPR, left, right);
2025-01-03 22:18:35 +01:00
break;
2025-01-31 09:46:17 +01:00
case boot::binary_operator::conjunction:
2025-02-14 08:05:03 +01:00
this->current_expression = build_bit_logic_operation(expression, left, right);
2024-12-28 14:33:35 +01:00
break;
2025-01-31 09:46:17 +01:00
case boot::binary_operator::disjunction:
2025-02-14 08:05:03 +01:00
this->current_expression = build_bit_logic_operation(expression, left, right);
break;
case boot::binary_operator::exclusive_disjunction:
this->current_expression = build_bit_logic_operation(expression, left, right);
2024-12-28 14:33:35 +01:00
break;
2025-01-31 09:46:17 +01:00
case boot::binary_operator::equals:
2025-02-12 00:56:21 +01:00
this->current_expression = build_equality_operation(expression, left, right);
2024-12-28 14:33:35 +01:00
break;
2025-01-31 09:46:17 +01:00
case boot::binary_operator::not_equals:
2025-02-12 00:56:21 +01:00
this->current_expression = build_equality_operation(expression, left, right);
2025-01-03 22:18:35 +01:00
break;
2025-02-15 00:38:46 +01:00
case boot::binary_operator::shift_left:
this->current_expression = build_binary_operation(
is_numeric_type(left_type) && right_type == elna_word_type_node,
expression, LSHIFT_EXPR, left, right, left_type);
break;
case boot::binary_operator::shift_right:
this->current_expression = build_binary_operation(
is_numeric_type(left_type) && right_type == elna_word_type_node,
expression, RSHIFT_EXPR, left, right, left_type);
break;
2024-12-28 14:33:35 +01:00
}
2024-12-27 10:51:46 +01:00
}
2024-12-27 23:38:25 +01:00
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::unary_expression *expression)
2025-01-10 23:17:18 +01:00
{
2025-01-13 11:55:19 +01:00
expression->operand().accept(this);
2025-02-14 08:05:03 +01:00
location_t location = get_location(&expression->position());
2025-01-13 11:55:19 +01:00
2025-01-10 23:17:18 +01:00
switch (expression->operation())
{
2025-01-31 09:46:17 +01:00
case boot::unary_operator::reference:
2025-01-30 23:09:51 +01:00
TREE_ADDRESSABLE(this->current_expression) = 1;
2025-02-14 08:05:03 +01:00
this->current_expression = build_fold_addr_expr_with_type_loc(location,
2025-01-30 23:09:51 +01:00
this->current_expression,
build_pointer_type_for_mode(TREE_TYPE(this->current_expression), VOIDmode, true));
TREE_NO_TRAMPOLINE(this->current_expression) = 1;
2025-01-10 23:17:18 +01:00
break;
2025-01-31 09:46:17 +01:00
case boot::unary_operator::negation:
2025-02-14 08:05:03 +01:00
if (TREE_TYPE(this->current_expression) == elna_bool_type_node)
{
this->current_expression = build1_loc(location, TRUTH_NOT_EXPR,
boolean_type_node, this->current_expression);
}
else if (is_integral_type(TREE_TYPE(this->current_expression)))
{
this->current_expression = build1_loc(location, BIT_NOT_EXPR,
TREE_TYPE(this->current_expression), this->current_expression);
}
else
{
error_at(location, "type '%s' cannot be negated",
print_type(TREE_TYPE(this->current_expression)).c_str());
this->current_expression = error_mark_node;
}
2025-01-13 11:55:19 +01:00
break;
2025-02-07 00:56:54 +01:00
case boot::unary_operator::minus:
2025-02-14 08:05:03 +01:00
if (is_integral_type(TREE_TYPE(this->current_expression)))
{
this->current_expression = fold_build1(NEGATE_EXPR, TREE_TYPE(this->current_expression),
this->current_expression);
}
else
{
error_at(location, "type '%s' cannot be negated",
print_type(TREE_TYPE(this->current_expression)).c_str());
this->current_expression = error_mark_node;
}
2025-01-10 23:17:18 +01:00
}
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::constant_definition *definition)
2024-12-29 22:28:53 +01:00
{
location_t definition_location = get_location(&definition->position());
2025-01-15 01:48:09 +01:00
definition->body().accept(this);
2024-12-29 22:28:53 +01:00
tree definition_tree = build_decl(definition_location, CONST_DECL,
2025-02-07 22:12:59 +01:00
get_identifier(definition->identifier.c_str()), TREE_TYPE(this->current_expression));
auto result = this->symbol_map->enter(definition->identifier, definition_tree);
2024-12-29 22:28:53 +01:00
if (result)
2024-12-29 22:28:53 +01:00
{
2025-01-15 01:48:09 +01:00
DECL_INITIAL(definition_tree) = this->current_expression;
2024-12-29 22:28:53 +01:00
TREE_CONSTANT(definition_tree) = 1;
TREE_READONLY(definition_tree) = 1;
2025-02-07 22:12:59 +01:00
TREE_PUBLIC(definition_tree) = definition->exported;
2024-12-29 22:28:53 +01:00
2025-02-12 00:56:21 +01:00
if (!lang_hooks.decls.global_bindings_p())
2025-02-07 22:12:59 +01:00
{
auto declaration_statement = build1_loc(definition_location, DECL_EXPR,
void_type_node, definition_tree);
2025-02-12 00:56:21 +01:00
append_statement(declaration_statement);
2025-02-07 22:12:59 +01:00
}
2024-12-29 22:28:53 +01:00
}
else
{
error_at(definition_location,
"variable '%s' already declared in this scope",
2025-02-07 22:12:59 +01:00
definition->identifier.c_str());
2024-12-29 22:28:53 +01:00
}
this->current_expression = NULL_TREE;
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::type_definition *definition)
2025-01-07 14:37:30 +01:00
{
location_t definition_location = get_location(&definition->position());
2025-02-07 22:12:59 +01:00
tree tree_type = build_type(definition->body());
2025-01-07 14:37:30 +01:00
tree definition_tree = build_decl(definition_location, TYPE_DECL,
2025-02-07 22:12:59 +01:00
get_identifier(definition->identifier.c_str()), tree_type);
auto result = this->symbol_map->enter(definition->identifier, tree_type);
2025-01-07 14:37:30 +01:00
if (result)
2025-01-07 14:37:30 +01:00
{
2025-02-07 22:12:59 +01:00
TREE_PUBLIC(definition_tree) = definition->exported;
TYPE_NAME(tree_type) = get_identifier(definition->identifier.c_str());
2025-01-07 14:37:30 +01:00
}
else
{
2025-02-07 22:12:59 +01:00
error_at(get_location(&definition->position()),
2025-01-07 14:37:30 +01:00
"type '%s' already declared in this scope",
2025-02-07 22:12:59 +01:00
definition->identifier.c_str());
2025-01-07 14:37:30 +01:00
}
}
2025-02-14 08:05:03 +01:00
tree generic_visitor::build_type(boot::top_type& type)
2024-12-27 23:38:25 +01:00
{
2025-02-14 08:05:03 +01:00
if (boot::basic_type *basic_type = type.is_basic())
2024-12-31 18:10:34 +01:00
{
2025-02-11 01:37:55 +01:00
tree symbol = this->lookup(basic_type->base_name());
2025-01-07 14:37:30 +01:00
2025-02-04 13:28:09 +01:00
if (symbol != NULL_TREE && TYPE_P(symbol))
2025-01-07 14:37:30 +01:00
{
2025-02-04 13:28:09 +01:00
return symbol;
2025-01-07 14:37:30 +01:00
}
2025-01-10 23:17:18 +01:00
error_at(get_location(&basic_type->position()),
"type '%s' not declared", basic_type->base_name().c_str());
return error_mark_node;
2025-01-01 23:02:19 +01:00
}
2025-02-14 08:05:03 +01:00
else if (boot::array_type *array_type = type.is_array())
2025-01-03 22:18:35 +01:00
{
2025-01-06 15:08:23 +01:00
tree lower_bound = build_int_cst_type(integer_type_node, 0);
tree upper_bound = build_int_cst_type(integer_type_node, array_type->size);
tree base_type = build_type(array_type->base());
2025-01-10 23:17:18 +01:00
if (base_type == NULL_TREE || base_type == error_mark_node)
2025-01-06 15:08:23 +01:00
{
2025-01-10 23:17:18 +01:00
return base_type;
2025-01-06 15:08:23 +01:00
}
tree range_type = build_range_type(integer_type_node, lower_bound, upper_bound);
return build_array_type(base_type, range_type);
2025-01-03 22:18:35 +01:00
}
2025-02-14 08:05:03 +01:00
else if (boot::pointer_type *pointer_type = type.is_pointer())
2025-01-10 23:17:18 +01:00
{
tree base_type = build_type(pointer_type->base());
if (base_type == NULL_TREE || base_type == error_mark_node)
{
return base_type;
}
return build_pointer_type_for_mode(base_type, VOIDmode, true);
}
2025-02-14 08:05:03 +01:00
else if (boot::record_type *record_type = type.is_record())
2025-01-09 22:40:39 +01:00
{
std::set<std::string> field_names;
tree record_type_node = make_node(RECORD_TYPE);
for (auto& field : record_type->fields)
2025-01-09 22:40:39 +01:00
{
if (field_names.find(field.first) != field_names.cend())
{
error_at(get_location(&field.second->position()), "repeated field name");
return error_mark_node;
}
field_names.insert(field.first);
tree field_type = build_type(*field.second);
if (field_type == NULL_TREE || field_type == error_mark_node)
{
return field_type;
}
2025-02-07 22:12:59 +01:00
tree field_declaration = build_field(get_location(&field.second->position()),
record_type_node, field.first, field_type);
2025-02-12 00:56:21 +01:00
TYPE_FIELDS(record_type_node) = chainon(TYPE_FIELDS(record_type_node), field_declaration);
2025-01-09 22:40:39 +01:00
}
layout_type(record_type_node);
return record_type_node;
}
2025-02-14 08:05:03 +01:00
else if (boot::union_type *union_type = type.is_union())
{
std::set<std::string> field_names;
tree union_type_node = make_node(UNION_TYPE);
for (auto& field : union_type->fields)
{
if (field_names.find(field.first) != field_names.cend())
{
error_at(get_location(&field.second->position()), "repeated field name");
return error_mark_node;
}
field_names.insert(field.first);
tree field_type = build_type(*field.second);
if (field_type == NULL_TREE || field_type == error_mark_node)
{
return field_type;
}
2025-02-07 22:12:59 +01:00
tree field_declaration = build_field(get_location(&field.second->position()),
union_type_node, field.first, field_type);
2025-02-12 00:56:21 +01:00
TYPE_FIELDS(union_type_node) = chainon(TYPE_FIELDS(union_type_node), field_declaration);
}
layout_type(union_type_node);
return union_type_node;
}
2025-01-06 15:08:23 +01:00
return NULL_TREE;
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::variable_declaration *declaration)
2025-01-06 15:08:23 +01:00
{
2025-02-14 08:05:03 +01:00
tree declaration_type = build_type(declaration->variable_type());
2025-01-10 23:17:18 +01:00
gcc_assert(declaration_type != NULL_TREE);
2025-01-06 15:08:23 +01:00
location_t declaration_location = get_location(&declaration->position());
2024-12-27 23:38:25 +01:00
tree declaration_tree = build_decl(declaration_location, VAR_DECL,
2025-02-07 22:12:59 +01:00
get_identifier(declaration->identifier.c_str()), declaration_type);
bool result = this->symbol_map->enter(declaration->identifier, declaration_tree);
2024-12-27 23:38:25 +01:00
2025-02-14 08:05:03 +01:00
if (is_pointer_type(declaration_type))
{
DECL_INITIAL(declaration_tree) = elna_pointer_nil_node;
}
if (!result)
{
error_at(declaration_location, "variable '%s' already declared in this scope",
2025-02-07 22:12:59 +01:00
declaration->identifier.c_str());
}
2025-02-12 00:56:21 +01:00
else if (lang_hooks.decls.global_bindings_p())
{
TREE_STATIC(declaration_tree) = 1;
varpool_node::get_create(declaration_tree);
varpool_node::finalize_decl(declaration_tree);
}
else
2024-12-27 23:38:25 +01:00
{
DECL_CONTEXT(declaration_tree) = current_function_decl;
2025-02-12 00:56:21 +01:00
f_names = chainon(f_names, declaration_tree);
2025-01-04 20:24:34 +01:00
2024-12-27 23:38:25 +01:00
auto declaration_statement = build1_loc(declaration_location, DECL_EXPR,
void_type_node, declaration_tree);
2025-02-12 00:56:21 +01:00
append_statement(declaration_statement);
2024-12-27 23:38:25 +01:00
}
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::variable_expression *expression)
2024-12-27 23:38:25 +01:00
{
2025-02-11 01:37:55 +01:00
auto symbol = this->lookup(expression->name());
2024-12-27 23:38:25 +01:00
2025-02-04 13:28:09 +01:00
if (symbol == NULL_TREE)
2024-12-27 23:38:25 +01:00
{
2024-12-28 14:33:35 +01:00
error_at(get_location(&expression->position()),
2024-12-27 23:38:25 +01:00
"variable '%s' not declared in the current scope",
expression->name().c_str());
this->current_expression = error_mark_node;
return;
}
2025-02-04 13:28:09 +01:00
this->current_expression = symbol;
2024-12-27 23:38:25 +01:00
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::array_access_expression *expression)
2025-01-07 14:37:30 +01:00
{
expression->base().accept(this);
tree designator = this->current_expression;
2025-02-12 20:47:47 +01:00
location_t location = get_location(&expression->position());
2025-01-07 14:37:30 +01:00
expression->index().accept(this);
2025-02-12 20:47:47 +01:00
if (!is_integral_type(TREE_TYPE(this->current_expression)))
{
error_at(location, "type '%s' cannot be used as index",
print_type(TREE_TYPE(this->current_expression)).c_str());
this->current_expression = error_mark_node;
return;
}
if (this->current_expression != elna_word_type_node)
{
this->current_expression = fold_convert(elna_word_type_node, this->current_expression);
}
tree offset = build2(MINUS_EXPR, elna_word_type_node,
this->current_expression, size_one_node);
2025-01-07 14:37:30 +01:00
2025-02-12 20:47:47 +01:00
if (is_array_type(TREE_TYPE(designator)))
{
tree element_type = TREE_TYPE(TREE_TYPE(designator));
2025-01-07 14:37:30 +01:00
2025-02-12 20:47:47 +01:00
this->current_expression = build4_loc(location,
ARRAY_REF, element_type, designator, offset, NULL_TREE, NULL_TREE);
}
else if (TREE_TYPE(designator) == elna_string_type_node)
{
tree string_ptr = build3_loc(location, COMPONENT_REF, TREE_TYPE(elna_string_ptr_field_node),
designator, elna_string_ptr_field_node, NULL_TREE);
tree target_pointer = do_pointer_arithmetic(boot::binary_operator::sum, string_ptr, offset);
this->current_expression = build1_loc(location, INDIRECT_REF,
elna_char_type_node, target_pointer);
}
else
{
error_at(location, "indexing is not allowed on type '%s'",
print_type(TREE_TYPE(designator)).c_str());
this->current_expression = error_mark_node;
}
2025-01-07 14:37:30 +01:00
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::field_access_expression *expression)
2025-01-10 23:17:18 +01:00
{
expression->base().accept(this);
2025-02-14 08:05:03 +01:00
location_t expression_location = get_location(&expression->position());
2025-01-10 23:17:18 +01:00
2025-02-14 08:05:03 +01:00
if (TYPE_P(this->current_expression))
2025-01-10 23:17:18 +01:00
{
2025-02-14 08:05:03 +01:00
if (expression->field() == "size")
2025-01-10 23:17:18 +01:00
{
2025-02-14 08:05:03 +01:00
this->current_expression = build1(CONVERT_EXPR, elna_word_type_node,
size_in_bytes(this->current_expression));
2025-01-10 23:17:18 +01:00
}
2025-02-14 08:05:03 +01:00
else if (expression->field() == "alignment")
{
this->current_expression = build_int_cstu(elna_word_type_node,
TYPE_ALIGN_UNIT(this->current_expression));
}
else if (expression->field() == "min" && is_integral_type(this->current_expression))
{
this->current_expression = TYPE_MIN_VALUE(this->current_expression);
}
else if (expression->field() == "max" && is_integral_type(this->current_expression))
{
this->current_expression = TYPE_MAX_VALUE(this->current_expression);
}
2025-02-14 08:05:03 +01:00
else
{
error_at(expression_location, "type '%s' does not have property '%s'",
print_type(this->current_expression).c_str(), expression->field().c_str());
this->current_expression = error_mark_node;
}
2025-01-10 23:17:18 +01:00
}
2025-02-14 08:05:03 +01:00
else if (is_aggregate_type(TREE_TYPE(this->current_expression)))
2025-01-10 23:17:18 +01:00
{
2025-02-14 08:05:03 +01:00
tree field_declaration = TYPE_FIELDS(TREE_TYPE(this->current_expression));
while (field_declaration != NULL_TREE)
{
tree declaration_name = DECL_NAME(field_declaration);
const char *identifier_pointer = IDENTIFIER_POINTER(declaration_name);
if (expression->field() == identifier_pointer)
{
break;
}
field_declaration = TREE_CHAIN(field_declaration);
}
if (field_declaration == NULL_TREE)
{
error_at(expression_location,
"record type does not have a field named '%s'",
expression->field().c_str());
this->current_expression = error_mark_node;
}
else
{
this->current_expression = build3_loc(expression_location, COMPONENT_REF,
TREE_TYPE(field_declaration), this->current_expression,
field_declaration, NULL_TREE);
}
2025-01-10 23:17:18 +01:00
}
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::dereference_expression *expression)
2025-01-10 23:17:18 +01:00
{
expression->base().accept(this);
this->current_expression = build1_loc(get_location(&expression->position()), INDIRECT_REF,
TREE_TYPE(TREE_TYPE(this->current_expression)), this->current_expression);
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::assign_statement *statement)
2024-12-27 23:38:25 +01:00
{
2025-01-07 14:37:30 +01:00
statement->lvalue().accept(this);
auto lvalue = this->current_expression;
2024-12-28 14:33:35 +01:00
auto statement_location = get_location(&statement->position());
2024-12-27 23:38:25 +01:00
statement->rvalue().accept(this);
2025-01-07 14:37:30 +01:00
if (TREE_CODE(lvalue) == CONST_DECL)
2024-12-29 22:28:53 +01:00
{
error_at(statement_location, "cannot modify constant '%s'",
2025-01-07 14:37:30 +01:00
statement->lvalue().is_variable()->name().c_str());
2024-12-29 22:28:53 +01:00
this->current_expression = error_mark_node;
}
else if (is_assignable_from(TREE_TYPE(lvalue), this->current_expression))
2025-02-04 13:28:09 +01:00
{
tree assignment = build2_loc(statement_location, MODIFY_EXPR,
void_type_node, lvalue, this->current_expression);
2025-02-12 00:56:21 +01:00
append_statement(assignment);
2025-02-04 13:28:09 +01:00
this->current_expression = NULL_TREE;
}
else
2024-12-27 23:38:25 +01:00
{
2024-12-29 22:28:53 +01:00
error_at(statement_location,
2025-02-13 22:54:47 +01:00
"cannot assign value of type '%s' to variable of type '%s'",
print_type(TREE_TYPE(this->current_expression)).c_str(),
print_type(TREE_TYPE(lvalue)).c_str());
2024-12-27 23:38:25 +01:00
this->current_expression = error_mark_node;
}
}
2024-12-28 14:33:35 +01:00
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::if_statement *statement)
2024-12-28 14:33:35 +01:00
{
2025-01-27 01:16:27 +01:00
tree endif_label_decl = build_label_decl("endif", UNKNOWN_LOCATION);
tree goto_endif = build1(GOTO_EXPR, void_type_node, endif_label_decl);
make_if_branch(statement->body(), goto_endif);
for (const auto branch : statement->branches)
{
make_if_branch(*branch, goto_endif);
}
if (statement->alternative() != nullptr)
{
2025-02-07 22:12:59 +01:00
enter_scope();
2025-01-27 01:16:27 +01:00
for (const auto body_statement : *statement->alternative())
{
body_statement->accept(this);
}
2025-02-12 00:56:21 +01:00
tree mapping = leave_scope();
append_statement(mapping);
2025-01-27 01:16:27 +01:00
}
tree endif_label_expr = build1(LABEL_EXPR, void_type_node, endif_label_decl);
2025-02-12 00:56:21 +01:00
append_statement(endif_label_expr);
2025-01-27 01:16:27 +01:00
this->current_expression = NULL_TREE;
}
2025-01-31 09:46:17 +01:00
void generic_visitor::make_if_branch(boot::conditional_statements& branch, tree goto_endif)
2025-01-27 01:16:27 +01:00
{
branch.prerequisite().accept(this);
2024-12-28 14:33:35 +01:00
2025-02-17 19:36:25 +01:00
if (TREE_TYPE(this->current_expression) != elna_bool_type_node)
2024-12-28 14:33:35 +01:00
{
2025-01-27 01:16:27 +01:00
error_at(get_location(&branch.prerequisite().position()),
2024-12-28 14:33:35 +01:00
"expected expression of boolean type but its type is %s",
print_type(TREE_TYPE(this->current_expression)).c_str());
2024-12-28 14:33:35 +01:00
this->current_expression = error_mark_node;
return;
}
2025-01-27 01:16:27 +01:00
tree then_label_decl = build_label_decl("then", UNKNOWN_LOCATION);
tree goto_then = build1(GOTO_EXPR, void_type_node, then_label_decl);
2024-12-28 14:33:35 +01:00
2025-01-27 01:16:27 +01:00
tree else_label_decl = build_label_decl("else", UNKNOWN_LOCATION);
tree goto_else = build1(GOTO_EXPR, void_type_node, else_label_decl);
2024-12-30 23:12:47 +01:00
2025-01-27 01:16:27 +01:00
auto cond_expr = build3(COND_EXPR, void_type_node, this->current_expression, goto_then, goto_else);
2025-02-12 00:56:21 +01:00
append_statement(cond_expr);
2024-12-28 14:33:35 +01:00
2025-01-27 01:16:27 +01:00
tree then_label_expr = build1(LABEL_EXPR, void_type_node, then_label_decl);
2025-02-12 00:56:21 +01:00
append_statement(then_label_expr);
2025-02-07 22:12:59 +01:00
enter_scope();
2024-12-28 14:33:35 +01:00
2025-01-27 01:16:27 +01:00
for (const auto body_statement : branch.statements)
2025-01-25 19:50:36 +01:00
{
body_statement->accept(this);
}
2025-02-12 00:56:21 +01:00
tree mapping = leave_scope();
append_statement(mapping);
append_statement(goto_endif);
2025-01-13 11:55:19 +01:00
2025-01-27 01:16:27 +01:00
tree else_label_expr = build1(LABEL_EXPR, void_type_node, else_label_decl);
2025-02-12 00:56:21 +01:00
append_statement(else_label_expr);
2024-12-28 14:33:35 +01:00
}
tree generic_visitor::build_label_decl(const char *name, location_t loc)
{
auto label_decl = build_decl(loc,
LABEL_DECL, get_identifier(name), void_type_node);
DECL_CONTEXT(label_decl) = current_function_decl;
2024-12-28 14:33:35 +01:00
return label_decl;
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::while_statement *statement)
2024-12-28 14:33:35 +01:00
{
2025-01-25 19:50:36 +01:00
auto prerequisite_location = get_location(&statement->body().prerequisite().position());
2024-12-28 14:33:35 +01:00
auto prerequisite_label_decl = build_label_decl("while_check", prerequisite_location);
auto prerequisite_label_expr = build1_loc(prerequisite_location, LABEL_EXPR,
void_type_node, prerequisite_label_decl);
2025-02-17 19:36:25 +01:00
auto goto_check = build1(GOTO_EXPR, void_type_node, prerequisite_label_decl);
2024-12-28 14:33:35 +01:00
2025-02-17 19:36:25 +01:00
append_statement(prerequisite_label_expr);
make_if_branch(statement->body(), goto_check);
2024-12-28 14:33:35 +01:00
2025-02-17 19:36:25 +01:00
for (const auto branch : statement->branches)
2025-01-25 19:50:36 +01:00
{
2025-02-17 19:36:25 +01:00
make_if_branch(*branch, goto_check);
2025-01-25 19:50:36 +01:00
}
2024-12-28 14:33:35 +01:00
this->current_expression = NULL_TREE;
}
2025-01-18 21:30:11 +01:00
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::call_statement *statement)
2025-01-18 21:30:11 +01:00
{
statement->body().accept(this);
2025-02-12 00:56:21 +01:00
append_statement(this->current_expression);
2025-02-07 22:12:59 +01:00
this->current_expression = NULL_TREE;
2025-01-18 21:30:11 +01:00
}
2025-01-31 09:46:17 +01:00
void generic_visitor::visit(boot::return_statement *statement)
2025-01-18 21:30:11 +01:00
{
2025-01-31 09:46:17 +01:00
boot::expression *return_expression = statement->return_expression();
2025-01-18 21:30:11 +01:00
if (return_expression == nullptr)
{
return;
}
return_expression->accept(this);
tree set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(current_function_decl),
2025-01-18 21:30:11 +01:00
this->current_expression);
tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result);
2025-02-12 00:56:21 +01:00
append_statement(return_stmt);
2025-02-07 22:12:59 +01:00
}
void generic_visitor::visit(boot::defer_statement *statement)
{
enter_scope();
for (boot::statement *const body_statement : statement->statements)
{
body_statement->accept(this);
}
2025-02-12 00:56:21 +01:00
defer(leave_scope());
2025-01-18 21:30:11 +01:00
}
2024-12-23 13:54:11 +01:00
}
}