summaryrefslogtreecommitdiff
path: root/gcc/elna-generic.cc
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-02-01 19:01:06 +0100
committerEugen Wissner <belka@caraus.de>2026-02-01 19:01:06 +0100
commit39197fe88ab23bf452e00569ef36b556b787a421 (patch)
tree11753e57712d2709a725bac4ff0ae6aa8508a41b /gcc/elna-generic.cc
parenta00f0d57b843736d603d749fc269d0208cec4e76 (diff)
downloadelna-39197fe88ab23bf452e00569ef36b556b787a421.tar.gz
Remove GCC glue code
Diffstat (limited to 'gcc/elna-generic.cc')
-rw-r--r--gcc/elna-generic.cc1277
1 files changed, 0 insertions, 1277 deletions
diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc
deleted file mode 100644
index b37b111..0000000
--- a/gcc/elna-generic.cc
+++ /dev/null
@@ -1,1277 +0,0 @@
-/* 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/>. */
-
-#include <array>
-
-#include "elna/gcc/elna-generic.h"
-#include "elna/gcc/elna-diagnostic.h"
-#include "elna/gcc/elna1.h"
-#include "elna/gcc/elna-builtins.h"
-
-#include "ggc.h"
-#include "function.h"
-#include "cgraph.h"
-#include "gimplify.h"
-#include "stringpool.h"
-#include "diagnostic.h"
-#include "realmpfr.h"
-#include "varasm.h"
-#include "fold-const.h"
-#include "langhooks.h"
-
-namespace elna::gcc
-{
- generic_visitor::generic_visitor(std::shared_ptr<symbol_table> symbol_table, elna::frontend::symbol_bag bag)
- : bag(bag), symbols(symbol_table)
- {
- }
-
- void generic_visitor::build_procedure_call(location_t call_location,
- tree procedure_address, const std::vector<frontend::expression *>& arguments)
- {
- vec<tree, va_gc> *argument_trees = nullptr;
- tree symbol_type = TREE_TYPE(TREE_TYPE(procedure_address));
-
- tree current_parameter = TYPE_ARG_TYPES(symbol_type);
-
- vec_alloc(argument_trees, arguments.size());
- for (frontend::expression *const argument : arguments)
- {
- location_t argument_location = get_location(&argument->position());
- if (VOID_TYPE_P(TREE_VALUE(current_parameter)))
- {
- error_at(argument_location, "Too many arguments, expected %i, got %lu",
- list_length(TYPE_ARG_TYPES(symbol_type)) - 1, arguments.size());
- this->current_expression = error_mark_node;
- break;
- }
- argument->accept(this);
- this->current_expression = prepare_rvalue(this->current_expression);
- 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 = fold_build_call_array_loc(call_location, TREE_TYPE(symbol_type),
- procedure_address, vec_safe_length(argument_trees), vec_safe_address(argument_trees));
-
- if (!VOID_TYPE_P(TREE_VALUE(current_parameter)))
- {
- error_at(call_location, "Too few arguments, expected %i, got %lu",
- list_length(TYPE_ARG_TYPES(symbol_type)) - 1, arguments.size());
- this->current_expression = error_mark_node;
- }
- else
- {
- this->current_expression = stmt;
- }
- }
-
- void generic_visitor::build_record_call(location_t call_location,
- tree symbol, const std::vector<frontend::expression *>& arguments)
- {
- vec<constructor_elt, va_gc> *tree_arguments = nullptr;
- tree record_fields = TYPE_FIELDS(symbol);
- for (frontend::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))
- {
- 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);
- }
- }
-
- void generic_visitor::build_assert_builtin(location_t call_location,
- const std::vector<frontend::expression *>& arguments)
- {
- if (arguments.size() != 1)
- {
- error_at(call_location, "assert expects exactly one boolean argument, got %lu", arguments.size());
- this->current_expression = error_mark_node;
- }
- else
- {
- arguments.at(0)->accept(this);
- tree argument_type = TREE_TYPE(this->current_expression);
-
- if (argument_type != elna_bool_type_node)
- {
- error_at(call_location, "assert expects exactly one boolean argument, got %s",
- print_type(argument_type).c_str());
- this->current_expression = error_mark_node;
- }
- tree constant_expression = extract_constant(this->current_expression);
- if (constant_expression == boolean_false_node)
- {
- this->current_expression = call_built_in(call_location, "__builtin_unreachable", void_type_node);
- }
- else if (constant_expression != boolean_true_node)
- {
- tree assert_expression = call_built_in(call_location, "__builtin_trap", void_type_node);
- this->current_expression = build3(COND_EXPR, void_type_node, this->current_expression,
- NULL_TREE, assert_expression);
- }
- else
- {
- this->current_expression = NULL_TREE;
- }
- }
- }
-
- bool generic_visitor::build_builtin_procedures(frontend::procedure_call *call)
- {
- location_t call_location = get_location(&call->position());
-
- if (frontend::variable_expression *named_call = call->callable().is_variable())
- {
- if (named_call->name == "assert")
- {
- build_assert_builtin(call_location, call->arguments);
- return true;
- }
- }
- return false;
- }
-
- void generic_visitor::visit(frontend::procedure_call *call)
- {
- if (build_builtin_procedures(call))
- {
- return;
- }
- location_t call_location = get_location(&call->position());
- call->callable().accept(this);
-
- tree expression_type = TYPE_P(this->current_expression)
- ? this->current_expression
- : TREE_TYPE(this->current_expression);
-
- if (TREE_CODE(expression_type) == RECORD_TYPE)
- {
- build_record_call(call_location, expression_type, call->arguments);
- }
- else if (TREE_CODE(expression_type) == FUNCTION_TYPE)
- {
- this->current_expression = build1(ADDR_EXPR,
- build_global_pointer_type(expression_type), this->current_expression);
- build_procedure_call(call_location, this->current_expression, call->arguments);
- }
- else if (POINTER_TYPE_P(expression_type) && TREE_CODE(TREE_TYPE(expression_type)) == FUNCTION_TYPE)
- {
- build_procedure_call(call_location, this->current_expression, call->arguments);
- }
- else
- {
- error_at(call_location, "'%s' cannot be called, it is neither a procedure nor record",
- print_type(expression_type).c_str());
- this->current_expression = error_mark_node;
- }
- }
-
- void generic_visitor::visit(frontend::cast_expression *expression)
- {
- tree cast_target = get_inner_alias(expression->expression_type, this->symbols->scope());
-
- expression->value().accept(this);
- tree cast_source = TREE_TYPE(this->current_expression);
-
- if (is_castable_type(cast_target) && (is_castable_type(cast_source)))
- {
- this->current_expression = build1_loc(get_location(&expression->position()), CONVERT_EXPR,
- cast_target, this->current_expression);
- }
- else
- {
- error_at(get_location(&expression->position()), "Type '%s' cannot be converted to '%s'",
- print_type(cast_source).c_str(), print_type(cast_target).c_str());
- this->current_expression = error_mark_node;
- }
- }
-
- void generic_visitor::visit(frontend::program *program)
- {
- visit(static_cast<frontend::unit *>(program));
-
- tree declaration_type = build_function_type_list(elna_int_type_node,
- elna_int_type_node,
- build_global_pointer_type(build_global_pointer_type(elna_char_type_node)),
- NULL_TREE);
- tree fndecl = build_fn_decl("main", declaration_type);
-
- tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node);
- DECL_CONTEXT(resdecl) = fndecl;
- DECL_RESULT(fndecl) = resdecl;
-
- push_struct_function(fndecl, false);
- DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc<language_function>();
-
- enter_scope();
-
- tree parameter_type = TYPE_ARG_TYPES(declaration_type);
- for (const char *argument_name : std::array<const char *, 2>{ "count", "parameters" })
- {
- 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);
-
- this->symbols->enter(argument_name, declaration_tree);
- DECL_ARGUMENTS(fndecl) = chainon(DECL_ARGUMENTS(fndecl), declaration_tree);
- parameter_type = TREE_CHAIN(parameter_type);
- }
- visit_statements(program->body);
- tree set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(fndecl),
- build_int_cst_type(integer_type_node, 0));
- tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result);
- append_statement(return_stmt);
- tree mapping = leave_scope();
-
- BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl;
- DECL_INITIAL(fndecl) = BIND_EXPR_BLOCK(mapping);
- DECL_SAVED_TREE(fndecl) = mapping;
-
- DECL_EXTERNAL(fndecl) = 0;
- DECL_PRESERVE_P(fndecl) = 1;
-
- pop_cfun();
- gimplify_function_tree(fndecl);
- cgraph_node::finalize_function(fndecl, true);
- }
-
- void generic_visitor::visit(frontend::unit *unit)
- {
- for (frontend::import_declaration *const declaration : unit->imports)
- {
- declaration->accept(this);
- }
- for (frontend::constant_declaration *const constant : unit->constants)
- {
- constant->accept(this);
- }
- for (frontend::variable_declaration *const variable : unit->variables)
- {
- variable->accept(this);
- }
- for (frontend::procedure_declaration *const procedure : unit->procedures)
- {
- procedure->accept(this);
- }
- }
-
- void generic_visitor::visit(frontend::procedure_declaration *definition)
- {
- tree fndecl = this->symbols->lookup(definition->identifier.name);
-
- if (!definition->body.has_value())
- {
- return;
- }
- push_struct_function(fndecl, false);
- DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc<language_function>();
-
- enter_scope();
- this->bag.enter(this->bag.lookup(definition->identifier.name)->is_procedure()->scope);
-
- tree argument_chain = DECL_ARGUMENTS(fndecl);
- for (; argument_chain != NULL_TREE; argument_chain = TREE_CHAIN(argument_chain))
- {
- this->symbols->enter(IDENTIFIER_POINTER(DECL_NAME(argument_chain)), argument_chain);
- }
- for (frontend::constant_declaration *const constant : definition->body.value().constants())
- {
- constant->accept(this);
- }
- for (frontend::variable_declaration *const variable : definition->body.value().variables())
- {
- variable->accept(this);
- }
- visit_statements(definition->body.value().body());
-
- tree mapping = leave_scope();
- this->bag.leave();
-
- BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl;
- DECL_INITIAL(fndecl) = BIND_EXPR_BLOCK(mapping);
- DECL_SAVED_TREE(fndecl) = mapping;
-
- DECL_PRESERVE_P(fndecl) = 1;
-
- pop_cfun();
- gimplify_function_tree(fndecl);
- cgraph_node::finalize_function(fndecl, true);
- }
-
- void generic_visitor::enter_scope()
- {
- this->symbols = std::make_shared<symbol_table>(this->symbols);
-
- // 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;
- }
-
- tree generic_visitor::leave_scope()
- {
- // 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);
-
- for (tree it = f_binding_level->blocks; it != NULL_TREE; it = BLOCK_CHAIN(it))
- {
- BLOCK_SUPERCONTEXT(it) = new_block;
- }
- tree bind_expr = build3(BIND_EXPR, void_type_node, variables, chain_defer(), new_block);
- this->symbols = this->symbols->scope();
-
- f_binding_level = f_binding_level->level_chain;
-
- if (f_binding_level != nullptr)
- {
- f_binding_level->blocks = chainon(f_binding_level->blocks, new_block);
- }
- return bind_expr;
- }
-
- void generic_visitor::visit(frontend::literal<std::int32_t> *literal)
- {
- this->current_expression = build_int_cst(elna_int_type_node, literal->value);
- }
-
- void generic_visitor::visit(frontend::literal<std::uint32_t> *literal)
- {
- this->current_expression = build_int_cstu(elna_word_type_node, literal->value);
- }
-
- void generic_visitor::visit(frontend::literal<double> *literal)
- {
- REAL_VALUE_TYPE real_value1;
-
- mpfr_t number;
- mpfr_init2(number, SIGNIFICAND_BITS);
- mpfr_set_d(number, literal->value, MPFR_RNDN);
-
- real_from_mpfr(&real_value1, number, double_type_node, MPFR_RNDN);
-
- this->current_expression = build_real(double_type_node, real_value1);
-
- mpfr_clear(number);
- }
-
- void generic_visitor::visit(frontend::literal<bool> *boolean)
- {
- this->current_expression = boolean->value ? boolean_true_node : boolean_false_node;
- }
-
- void generic_visitor::visit(frontend::literal<unsigned char> *character)
- {
- this->current_expression = build_int_cstu(elna_char_type_node, character->value);
- }
-
- void generic_visitor::visit(frontend::literal<nullptr_t> *)
- {
- this->current_expression = elna_pointer_nil_node;
- }
-
- void generic_visitor::visit(frontend::literal<std::string> *string)
- {
- tree index_constant = build_int_cstu(elna_word_type_node, string->value.size());
- tree string_type = build_array_type(elna_char_type_node, build_index_type(index_constant));
-
- tree string_literal = build_string(string->value.size(), string->value.c_str());
- TREE_TYPE(string_literal) = string_type;
- TREE_CONSTANT(string_literal) = 1;
- TREE_READONLY(string_literal) = 1;
- TREE_STATIC(string_literal) = 1;
-
- string_type = TREE_TYPE(elna_string_ptr_field_node);
- string_literal = build4(ARRAY_REF, elna_char_type_node,
- string_literal, integer_zero_node, NULL_TREE, NULL_TREE);
- string_literal = build1(ADDR_EXPR, string_type, string_literal);
-
- vec<constructor_elt, va_gc> *elms = nullptr;
- CONSTRUCTOR_APPEND_ELT(elms, elna_string_ptr_field_node, string_literal);
- CONSTRUCTOR_APPEND_ELT(elms, elna_string_length_field_node, index_constant);
-
- this->current_expression = build_constructor(elna_string_type_node, elms);
- }
-
- tree generic_visitor::build_arithmetic_operation(frontend::binary_expression *expression,
- tree_code operator_code, tree left, tree right)
- {
- return build_binary_operation(is_numeric_type(TREE_TYPE(left)),
- expression, operator_code, left, right, TREE_TYPE(left));
- }
-
- tree generic_visitor::build_comparison_operation(frontend::binary_expression *expression,
- tree_code operator_code, tree left, tree right)
- {
- return build_binary_operation(is_numeric_type(TREE_TYPE(left)) || POINTER_TYPE_P(TREE_TYPE(left)),
- expression, operator_code, left, right, elna_bool_type_node);
- }
-
- tree generic_visitor::build_bit_logic_operation(frontend::binary_expression *expression, tree left, tree right)
- {
- 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() == frontend::binary_operator::conjunction)
- {
- bit_code = BIT_AND_EXPR;
- logical_code = TRUTH_ANDIF_EXPR;
- }
- else if (expression->operation() == frontend::binary_operator::disjunction)
- {
- bit_code = BIT_IOR_EXPR;
- logical_code = TRUTH_ORIF_EXPR;
- }
- else if (expression->operation() == frontend::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::frontend::print_binary_operator(expression->operation()));
- return error_mark_node;
- }
- }
-
- tree generic_visitor::build_equality_operation(frontend::binary_expression *expression, tree left, tree right)
- {
- location_t expression_location = get_location(&expression->position());
- tree_code equality_code, combination_code;
-
- if (expression->operation() == frontend::binary_operator::equals)
- {
- equality_code = EQ_EXPR;
- combination_code = TRUTH_ANDIF_EXPR;
- }
- else if (expression->operation() == frontend::binary_operator::not_equals)
- {
- equality_code = NE_EXPR;
- combination_code = TRUTH_ORIF_EXPR;
- }
- else
- {
- gcc_unreachable();
- }
- if (TREE_TYPE(left) == elna_string_type_node)
- {
- 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);
-
- 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);
-
- tree length_equality = build2(equality_code, elna_bool_type_node, lhs_length, rhs_length);
- tree memcmp_call = call_built_in(UNKNOWN_LOCATION, "__builtin_memcmp", integer_type_node,
- 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);
- }
- }
-
- void generic_visitor::visit(frontend::binary_expression *expression)
- {
- expression->lhs().accept(this);
- tree left = this->current_expression;
- tree left_type = get_qualified_type(TREE_TYPE(left), TYPE_UNQUALIFIED);
-
- expression->rhs().accept(this);
- tree right = this->current_expression;
- tree right_type = get_qualified_type(TREE_TYPE(right), TYPE_UNQUALIFIED);
-
- location_t expression_location = get_location(&expression->position());
-
- if ((POINTER_TYPE_P(left_type) || POINTER_TYPE_P(right_type))
- && (expression->operation() == frontend::binary_operator::sum
- || expression->operation() == frontend::binary_operator::subtraction))
- {
- this->current_expression = do_pointer_arithmetic(expression->operation(),
- left, right, expression_location);
- if (this->current_expression == error_mark_node)
- {
- error_at(expression_location,
- "invalid operation %s on a pointer and an integral type",
- frontend::print_binary_operator(expression->operation()));
- }
- else if (TREE_TYPE(this->current_expression) == ssizetype)
- {
- this->current_expression = fold_convert(elna_int_type_node, this->current_expression);
- }
- return;
- }
- if (left_type != right_type
- && !are_compatible_pointers(left_type, right)
- && !are_compatible_pointers(right_type, left)
- && !(is_integral_type(left_type) && right_type == elna_word_type_node))
- {
- 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(),
- frontend::print_binary_operator(expression->operation()));
- this->current_expression = error_mark_node;
- return;
- }
- switch (expression->operation())
- {
- case frontend::binary_operator::sum:
- this->current_expression = build_arithmetic_operation(expression, PLUS_EXPR, left, right);
- break;
- case frontend::binary_operator::subtraction:
- this->current_expression = build_arithmetic_operation(expression, MINUS_EXPR, left, right);
- break;
- case frontend::binary_operator::division:
- this->current_expression = build_arithmetic_operation(expression, TRUNC_DIV_EXPR, left, right);
- break;
- case frontend::binary_operator::remainder:
- this->current_expression = build_arithmetic_operation(expression, TRUNC_MOD_EXPR, left, right);
- break;
- case frontend::binary_operator::multiplication:
- this->current_expression = build_arithmetic_operation(expression, MULT_EXPR, left, right);
- break;
- case frontend::binary_operator::less:
- this->current_expression = build_comparison_operation(expression, LT_EXPR, left, right);
- break;
- case frontend::binary_operator::greater:
- this->current_expression = build_comparison_operation(expression, GT_EXPR, left, right);
- break;
- case frontend::binary_operator::less_equal:
- this->current_expression = build_comparison_operation(expression, LE_EXPR, left, right);
- break;
- case frontend::binary_operator::greater_equal:
- this->current_expression = build_comparison_operation(expression, GE_EXPR, left, right);
- break;
- case frontend::binary_operator::conjunction:
- this->current_expression = build_bit_logic_operation(expression, left, right);
- break;
- case frontend::binary_operator::disjunction:
- this->current_expression = build_bit_logic_operation(expression, left, right);
- break;
- case frontend::binary_operator::exclusive_disjunction:
- this->current_expression = build_bit_logic_operation(expression, left, right);
- break;
- case frontend::binary_operator::equals:
- this->current_expression = build_equality_operation(expression, left, right);
- break;
- case frontend::binary_operator::not_equals:
- this->current_expression = build_equality_operation(expression, left, right);
- break;
- case frontend::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 frontend::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;
- }
- }
-
- void generic_visitor::visit(frontend::unary_expression *expression)
- {
- expression->operand().accept(this);
- location_t location = get_location(&expression->position());
-
- switch (expression->operation())
- {
- case frontend::unary_operator::reference:
- this->current_expression = prepare_rvalue(this->current_expression);
- TREE_ADDRESSABLE(this->current_expression) = 1;
- this->current_expression = build_fold_addr_expr_with_type_loc(location,
- this->current_expression,
- build_global_pointer_type(TREE_TYPE(this->current_expression)));
- TREE_NO_TRAMPOLINE(this->current_expression) = 1;
- break;
- case frontend::unary_operator::negation:
- 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;
- }
- break;
- case frontend::unary_operator::minus:
- 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;
- }
- }
- }
-
- void generic_visitor::visit(frontend::constant_declaration *definition)
- {
- location_t definition_location = get_location(&definition->position());
- definition->body().accept(this);
-
- if (assert_constant(definition_location))
- {
- this->current_expression = fold_init(this->current_expression);
- }
- else
- {
- this->current_expression = NULL_TREE;
- return;
- }
- tree definition_tree = build_decl(definition_location, CONST_DECL,
- get_identifier(definition->identifier.name.c_str()), TREE_TYPE(this->current_expression));
- auto result = this->symbols->enter(definition->identifier.name, definition_tree);
-
- if (result)
- {
- DECL_INITIAL(definition_tree) = this->current_expression;
- TREE_CONSTANT(definition_tree) = 1;
- TREE_READONLY(definition_tree) = 1;
- TREE_PUBLIC(definition_tree) = definition->identifier.exported;
-
- if (!lang_hooks.decls.global_bindings_p())
- {
- auto declaration_statement = build1_loc(definition_location, DECL_EXPR,
- void_type_node, definition_tree);
- append_statement(declaration_statement);
- }
- }
- else
- {
- error_at(definition_location, "Variable '%s' already declared in this scope",
- definition->identifier.name.c_str());
- }
- this->current_expression = NULL_TREE;
- }
-
- void generic_visitor::visit(frontend::variable_declaration *declaration)
- {
- for (const auto& variable_identifier : declaration->identifiers)
- {
- location_t declaration_location = get_location(&declaration->position());
- tree declaration_tree = this->symbols->lookup(variable_identifier.name);
-
- if (declaration_tree == NULL_TREE)
- {
- auto variable_symbol = this->bag.lookup(variable_identifier.name)->is_variable();
-
- declaration_tree = declare_variable(variable_identifier.name, *variable_symbol, this->symbols);
- }
- // Set initializer if given.
- if (declaration->body != nullptr)
- {
- declaration->body->accept(this);
- if (is_assignable_from(TREE_TYPE(declaration_tree), this->current_expression))
- {
- DECL_INITIAL(declaration_tree) = this->current_expression;
- }
- else
- {
- error_at(declaration_location, "Cannot initialize variable of type '%s' with a value of type '%s'",
- print_type(TREE_TYPE(declaration_tree)).c_str(),
- print_type(TREE_TYPE(this->current_expression)).c_str());
- }
- }
- else if (!declaration->is_extern && POINTER_TYPE_P(TREE_TYPE(declaration_tree)))
- {
- DECL_INITIAL(declaration_tree) = elna_pointer_nil_node;
- }
- this->current_expression = NULL_TREE;
-
- if (lang_hooks.decls.global_bindings_p())
- {
- TREE_STATIC(declaration_tree) = !variable_identifier.exported && !declaration->is_extern;
- varpool_node::get_create(declaration_tree);
- varpool_node::finalize_decl(declaration_tree);
- }
- else
- {
- DECL_CONTEXT(declaration_tree) = current_function_decl;
- f_names = chainon(f_names, declaration_tree);
-
- auto declaration_statement = build1_loc(declaration_location, DECL_EXPR,
- void_type_node, declaration_tree);
- append_statement(declaration_statement);
- }
- }
- }
-
- void generic_visitor::visit(frontend::variable_expression *expression)
- {
- auto symbol = this->symbols->lookup(expression->name);
-
- if (symbol == NULL_TREE)
- {
- error_at(get_location(&expression->position()), "Symbol '%s' not declared in the current scope",
- expression->name.c_str());
- this->current_expression = error_mark_node;
- }
- else
- {
- this->current_expression = symbol;
- }
- }
-
- void generic_visitor::visit(frontend::array_access_expression *expression)
- {
- expression->base().accept(this);
- tree designator = this->current_expression;
- location_t location = get_location(&expression->position());
-
- expression->index().accept(this);
- 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;
- }
- tree offset = fold_convert(elna_word_type_node, this->current_expression);
-
- if (TREE_CODE(TREE_TYPE(designator)) == ARRAY_TYPE)
- {
- tree element_type = TREE_TYPE(TREE_TYPE(designator));
-
- this->current_expression = build4_loc(location,
- ARRAY_REF, element_type, designator, offset, size_one_node, NULL_TREE);
- }
- else if (TREE_TYPE(designator) == elna_string_type_node)
- {
- offset = build2(MINUS_EXPR, elna_word_type_node, offset, size_one_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(frontend::binary_operator::sum, string_ptr, offset, location);
-
- 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;
- }
- }
-
- bool generic_visitor::expect_trait_type_only(frontend::traits_expression *trait)
- {
- if (trait->parameters.size() != 1)
- {
- error_at(get_location(&trait->position()), "Trait '%s' expects 1 argument, got %lu",
- trait->name.c_str(), trait->parameters.size());
- this->current_expression = error_mark_node;
- return false;
- }
- this->current_expression = get_inner_alias(trait->types.front(), this->symbols);
-
- return this->current_expression != error_mark_node;
- }
-
- bool generic_visitor::expect_trait_for_integral_type(frontend::traits_expression *trait)
- {
- if (!expect_trait_type_only(trait))
- {
- return false;
- }
- else if (!is_integral_type(this->current_expression) && TREE_CODE(this->current_expression) != ENUMERAL_TYPE)
- {
- error_at(get_location(&trait->position()), "Type '%s' does not support trait '%s'",
- print_type(this->current_expression).c_str(), trait->name.c_str());
- this->current_expression = error_mark_node;
- return false;
- }
- return true;
- }
-
- void generic_visitor::visit(frontend::traits_expression *trait)
- {
- location_t trait_location = get_location(&trait->position());
-
- if (trait->name == "size")
- {
- if (expect_trait_type_only(trait))
- {
- this->current_expression = build1_loc(trait_location, CONVERT_EXPR, elna_word_type_node,
- size_in_bytes(this->current_expression));
- }
- }
- else if (trait->name == "alignment")
- {
- if (expect_trait_type_only(trait))
- {
- this->current_expression = build_int_cstu(elna_word_type_node,
- TYPE_ALIGN_UNIT(this->current_expression));
- }
- }
- else if (trait->name == "min")
- {
- if (expect_trait_for_integral_type(trait))
- {
- this->current_expression = TYPE_MIN_VALUE(this->current_expression);
- }
- }
- else if (trait->name == "max")
- {
- if (expect_trait_for_integral_type(trait))
- {
- this->current_expression = TYPE_MAX_VALUE(this->current_expression);
- }
- }
- else if (trait->name == "offset")
- {
- if (trait->parameters.size() != 2)
- {
- error_at(trait_location, "Trait '%s' expects 2 arguments, got %lu",
- trait->name.c_str(), trait->parameters.size());
- this->current_expression = error_mark_node;
- return;
- }
- this->current_expression = get_inner_alias(trait->types.front(), this->symbols);
- auto field_type = trait->parameters.at(1)->is_named();
-
- if (field_type == nullptr)
- {
- error_at(trait_location,
- "The second argument to the offset trait is expected to be a field name,"
- "got a type expression");
- this->current_expression = error_mark_node;
- return;
- }
- tree field_declaration = find_field_by_name(trait_location, this->current_expression, field_type->name);
-
- if (field_declaration != error_mark_node)
- {
- this->current_expression = build1(CONVERT_EXPR, elna_word_type_node,
- byte_position(field_declaration));
- }
- else
- {
- this->current_expression = error_mark_node;
- }
- }
- else
- {
- error_at(get_location(&trait->position()), "Trait '%s' is unknown", trait->name.c_str());
- this->current_expression = error_mark_node;
- }
- }
-
- void generic_visitor::visit(frontend::field_access_expression *expression)
- {
- expression->base().accept(this);
- location_t expression_location = get_location(&expression->position());
- tree aggregate_type = TREE_TYPE(this->current_expression);
-
- if (TREE_CODE(aggregate_type) == ARRAY_TYPE && expression->field() == "length")
- {
- this->current_expression = convert(build_qualified_type(elna_word_type_node, TYPE_QUAL_CONST),
- TYPE_MAX_VALUE(TYPE_DOMAIN(aggregate_type)));
- }
- else if (TREE_CODE(aggregate_type) == ARRAY_TYPE && expression->field() == "ptr")
- {
- tree ptr_type = build_global_pointer_type(TREE_TYPE(aggregate_type));
- this->current_expression = build1(ADDR_EXPR,
- build_qualified_type(ptr_type, TYPE_QUAL_CONST), this->current_expression);
- }
- else if (TREE_CODE(aggregate_type) == ENUMERAL_TYPE)
- {
- tree iterator{ NULL_TREE };
-
- for (iterator = TYPE_VALUES(aggregate_type); iterator != NULL_TREE; iterator = TREE_CHAIN(iterator))
- {
- if (IDENTIFIER_POINTER(TREE_PURPOSE(iterator)) == expression->field())
- {
- this->current_expression = TREE_VALUE(iterator);
- return;
- }
- }
- this->current_expression = error_mark_node;
- error_at(expression_location, "Unknown enumeration member '%s'", expression->field().c_str());
- }
- else
- {
- tree field_declaration = find_field_by_name(expression_location,
- TREE_TYPE(this->current_expression), expression->field());
-
- if (field_declaration != error_mark_node)
- {
- this->current_expression = build3_loc(expression_location, COMPONENT_REF,
- TREE_TYPE(field_declaration), this->current_expression,
- field_declaration, NULL_TREE);
- }
- }
- }
-
- void generic_visitor::visit(frontend::dereference_expression *expression)
- {
- expression->base().accept(this);
- location_t expression_location = get_location(&expression->position());
- tree expression_type = TREE_TYPE(this->current_expression);
-
- if (POINTER_TYPE_P(expression_type))
- {
- this->current_expression = build1_loc(expression_location, INDIRECT_REF,
- TREE_TYPE(expression_type), this->current_expression);
- }
- else
- {
- error_at(expression_location, "Type '%s' cannot be dereferenced, it is not a pointer",
- print_type(expression_type).c_str());
- this->current_expression = error_mark_node;
- }
- }
-
- void generic_visitor::visit(frontend::assign_statement *statement)
- {
- statement->lvalue().accept(this);
-
- tree lvalue = this->current_expression;
- location_t statement_location = get_location(&statement->position());
-
- statement->rvalue().accept(this);
- tree rvalue = prepare_rvalue(this->current_expression);
-
- if (TREE_CODE(lvalue) == CONST_DECL)
- {
- error_at(statement_location, "Cannot modify constant '%s'",
- statement->lvalue().is_variable()->name.c_str());
- }
- else if (TYPE_READONLY(TREE_TYPE(lvalue)))
- {
- error_at(statement_location, "Cannot modify a constant expression of type '%s'",
- print_type(TREE_TYPE(lvalue)).c_str());
- }
- else if (is_assignable_from(TREE_TYPE(lvalue), rvalue))
- {
- tree assignment = build2_loc(statement_location, MODIFY_EXPR, void_type_node, lvalue, rvalue);
-
- append_statement(assignment);
- }
- else
- {
- error_at(statement_location, "Cannot assign value of type '%s' to variable of type '%s'",
- print_type(TREE_TYPE(rvalue)).c_str(),
- print_type(TREE_TYPE(lvalue)).c_str());
- }
- this->current_expression = NULL_TREE;
- }
-
- void generic_visitor::visit(frontend::if_statement *statement)
- {
- tree endif_label_decl = create_artificial_label(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)
- {
- enter_scope();
- visit_statements(*statement->alternative);
- tree mapping = leave_scope();
- append_statement(mapping);
- }
- tree endif_label_expr = build1(LABEL_EXPR, void_type_node, endif_label_decl);
- append_statement(endif_label_expr);
- this->current_expression = NULL_TREE;
- }
-
- void generic_visitor::make_if_branch(frontend::conditional_statements& branch, tree goto_endif)
- {
- branch.prerequisite().accept(this);
-
- if (TREE_TYPE(this->current_expression) != elna_bool_type_node)
- {
- error_at(get_location(&branch.prerequisite().position()),
- "Expected expression of boolean type but its type is %s",
- print_type(TREE_TYPE(this->current_expression)).c_str());
- this->current_expression = error_mark_node;
- return;
- }
- tree then_label_decl = build_label_decl("then", UNKNOWN_LOCATION);
- tree goto_then = build1(GOTO_EXPR, void_type_node, then_label_decl);
-
- tree else_label_decl = build_label_decl("else", UNKNOWN_LOCATION);
- tree goto_else = build1(GOTO_EXPR, void_type_node, else_label_decl);
-
- auto cond_expr = build3(COND_EXPR, void_type_node, this->current_expression, goto_then, goto_else);
- append_statement(cond_expr);
-
- tree then_label_expr = build1(LABEL_EXPR, void_type_node, then_label_decl);
- append_statement(then_label_expr);
- enter_scope();
-
- visit_statements(branch.statements);
- tree mapping = leave_scope();
- append_statement(mapping);
- append_statement(goto_endif);
-
- tree else_label_expr = build1(LABEL_EXPR, void_type_node, else_label_decl);
- append_statement(else_label_expr);
- }
-
- void generic_visitor::visit(frontend::import_declaration *)
- {
- }
-
- void generic_visitor::visit(frontend::while_statement *statement)
- {
- location_t prerequisite_location = get_location(&statement->body().prerequisite().position());
- tree prerequisite_label_decl = build_label_decl("while_do", prerequisite_location);
- auto prerequisite_label_expr = build1_loc(prerequisite_location, LABEL_EXPR,
- void_type_node, prerequisite_label_decl);
- auto goto_check = build1(GOTO_EXPR, void_type_node, prerequisite_label_decl);
- tree branch_end_declaration = build_label_decl("while_end", UNKNOWN_LOCATION);
- tree branch_end_expression = build1_loc(UNKNOWN_LOCATION, LABEL_EXPR, void_type_node, branch_end_declaration);
-
- append_statement(prerequisite_label_expr);
- make_if_branch(statement->body(), goto_check);
-
- for (const auto branch : statement->branches)
- {
- make_if_branch(*branch, goto_check);
- }
- append_statement(branch_end_expression);
- this->current_expression = NULL_TREE;
- }
-
- void generic_visitor::visit_statements(const std::vector<frontend::statement *>& statements)
- {
- for (frontend::statement *const statement : statements)
- {
- statement->accept(this);
-
- if (this->current_expression != NULL_TREE && this->current_expression != error_mark_node)
- {
- append_statement(this->current_expression);
- this->current_expression = NULL_TREE;
- }
- }
- }
-
- void generic_visitor::visit(frontend::return_statement *statement)
- {
- frontend::expression *return_expression = &statement->return_expression();
- location_t statement_position = get_location(&statement->position());
- tree set_result{ NULL_TREE };
- tree return_type = TREE_TYPE(TREE_TYPE(current_function_decl));
-
- if (TREE_THIS_VOLATILE(current_function_decl) == 1)
- {
- error_at(statement_position, "This procedure is not allowed to return");
- return;
- }
- if (return_expression != nullptr)
- {
- return_expression->accept(this);
-
- set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(current_function_decl),
- this->current_expression);
- }
- if (return_type == void_type_node && set_result != NULL_TREE)
- {
- error_at(statement_position, "Proper procedure is not allowed to return a value");
- }
- else if (return_type != void_type_node && set_result == NULL_TREE)
- {
- error_at(statement_position, "Procedure is expected to return a value of type '%s'",
- print_type(return_type).c_str());
- }
- else if (return_type != void_type_node && !is_assignable_from(return_type, this->current_expression))
- {
- error_at(statement_position, "Cannot return '%s' from a procedure returning '%s'",
- print_type(return_type).c_str(),
- print_type(TREE_TYPE(this->current_expression)).c_str());
- }
- else
- {
- tree return_stmt = build1_loc(statement_position, RETURN_EXPR, void_type_node, set_result);
- append_statement(return_stmt);
- }
- this->current_expression = NULL_TREE;
- }
-
- void generic_visitor::visit(frontend::defer_statement *statement)
- {
- enter_scope();
- visit_statements(statement->statements);
- defer(leave_scope());
- }
-
- void generic_visitor::visit(frontend::case_statement *statement)
- {
- statement->condition().accept(this);
- tree condition_expression = this->current_expression;
- tree unqualified_condition = get_qualified_type(TREE_TYPE(this->current_expression), TYPE_UNQUALIFIED);
-
- if (!INTEGRAL_TYPE_P(unqualified_condition))
- {
- error_at(get_location(&statement->condition().position()),
- "Case expressions can only be integral numbers, characters and enumerations, given '%s'",
- print_type(unqualified_condition).c_str());
- this->current_expression = NULL_TREE;
- return;
- }
- tree end_label_declaration = create_artificial_label(get_location(&statement->position()));
- tree switch_statements = alloc_stmt_list();
-
- for (const frontend::switch_case& case_block : statement->cases)
- {
- for (frontend::expression *const case_label : case_block.labels)
- {
- case_label->accept(this);
- location_t case_location = get_location(&case_label->position());
-
- if (assert_constant(case_location)
- && !is_assignable_from(unqualified_condition, this->current_expression))
- {
- error_at(case_location, "Case type '%s' does not match the expression type '%s'",
- print_type(TREE_TYPE(this->current_expression)).c_str(),
- print_type(unqualified_condition).c_str());
- this->current_expression = error_mark_node;
- }
- tree case_label_declaration = create_artificial_label(case_location);
- tree case_expression = build_case_label(this->current_expression, NULL_TREE, case_label_declaration);
-
- append_to_statement_list(case_expression, &switch_statements);
- }
- enter_scope();
- visit_statements(case_block.statements);
- append_to_statement_list(leave_scope(), &switch_statements);
- tree goto_end = build1(GOTO_EXPR, void_type_node, end_label_declaration);
-
- append_to_statement_list(goto_end, &switch_statements);
- TREE_USED(end_label_declaration) = 1;
- }
- if (statement->alternative != nullptr)
- {
- tree case_label_declaration = create_artificial_label(UNKNOWN_LOCATION);
- tree case_expression = build_case_label(NULL_TREE, NULL_TREE, case_label_declaration);
-
- append_to_statement_list(case_expression, &switch_statements);
-
- enter_scope();
- visit_statements(*statement->alternative);
- append_to_statement_list(leave_scope(), &switch_statements);
-
- TREE_USED(end_label_declaration) = 1;
- }
- tree switch_expression = build2(SWITCH_EXPR, TREE_TYPE(condition_expression),
- condition_expression, switch_statements);
-
- append_statement(switch_expression);
-
- tree end_label_expression = build1(LABEL_EXPR, void_type_node, end_label_declaration);
- append_statement(end_label_expression);
-
- this->current_expression = NULL_TREE;
- }
-
- bool generic_visitor::assert_constant(location_t expression_location)
- {
- tree constant_expression = extract_constant(this->current_expression);
-
- if (constant_expression == NULL_TREE)
- {
- error_at(expression_location, "Expected a constant expression");
- this->current_expression = error_mark_node;
- }
- else
- {
- this->current_expression = constant_expression;
- }
- return this->current_expression != error_mark_node;
- }
-}