2025-02-09 12:30:31 +01:00
|
|
|
/* Visitor generating a GENERIC tree.
|
2025-02-08 23:02:27 +01:00
|
|
|
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"
|
2024-12-23 13:54:11 +01:00
|
|
|
|
|
|
|
#include "input.h"
|
|
|
|
#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-01-09 22:40:39 +01:00
|
|
|
#include <set>
|
2024-12-23 13:54:11 +01:00
|
|
|
|
|
|
|
namespace elna
|
|
|
|
{
|
|
|
|
namespace gcc
|
|
|
|
{
|
2025-01-31 09:46:17 +01:00
|
|
|
generic_visitor::generic_visitor(std::shared_ptr<boot::symbol_table<tree>> symbol_table)
|
2025-01-12 10:35:24 +01:00
|
|
|
{
|
2025-01-17 10:11:40 +01:00
|
|
|
this->symbol_map = symbol_table;
|
2025-01-12 10:35:24 +01:00
|
|
|
}
|
|
|
|
|
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-04 13:28:09 +01:00
|
|
|
tree symbol = this->symbol_map->lookup(expression->name());
|
2024-12-23 13:54:11 +01:00
|
|
|
|
2025-02-04 13:28:09 +01:00
|
|
|
if (symbol == NULL_TREE)
|
2025-01-11 23:20:23 +01:00
|
|
|
{
|
2025-01-28 11:21:02 +01:00
|
|
|
error_at(get_location(&expression->position()),
|
2025-01-11 13:32:37 +01:00
|
|
|
"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
|
|
|
return;
|
|
|
|
}
|
|
|
|
tree return_type = TREE_TYPE(TREE_TYPE(symbol));
|
|
|
|
tree fndecl_type = build_function_type(return_type, TYPE_ARG_TYPES(symbol));
|
|
|
|
tree printf_fn = build1(ADDR_EXPR, build_pointer_type(fndecl_type), symbol);
|
|
|
|
|
|
|
|
std::vector<tree> arguments(expression->arguments().size());
|
|
|
|
for (std::size_t i = 0; i < expression->arguments().size(); ++i)
|
|
|
|
{
|
|
|
|
expression->arguments().at(i)->accept(this);
|
|
|
|
arguments[i] = this->current_expression;
|
|
|
|
}
|
|
|
|
tree stmt = build_call_array_loc(get_location(&expression->position()),
|
|
|
|
return_type, printf_fn, arguments.size(), arguments.data());
|
|
|
|
|
|
|
|
if (return_type == void_type_node)
|
|
|
|
{
|
2025-02-07 22:12:59 +01:00
|
|
|
this->scope.front().append_statement(stmt);
|
2025-02-04 13:28:09 +01:00
|
|
|
this->current_expression = NULL_TREE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this->current_expression = stmt;
|
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-01-31 09:46:17 +01:00
|
|
|
void generic_visitor::visit(boot::size_of_expression *expression)
|
2025-01-29 12:55:52 +01:00
|
|
|
{
|
|
|
|
auto body_type = build_type(expression->body());
|
|
|
|
|
2025-02-05 13:24:50 +01:00
|
|
|
this->current_expression = build1(CONVERT_EXPR, this->symbol_map->lookup("Word"), size_in_bytes(body_type));
|
2025-01-31 09:46:17 +01:00
|
|
|
}
|
|
|
|
|
2025-02-02 08:22:40 +01:00
|
|
|
bool generic_visitor::is_numeric_type(tree type)
|
|
|
|
{
|
|
|
|
return is_integral_type(type)
|
2025-02-04 13:28:09 +01:00
|
|
|
|| type == this->symbol_map->lookup("Float");
|
2025-02-02 08:22:40 +01:00
|
|
|
}
|
|
|
|
|
2025-01-31 09:46:17 +01:00
|
|
|
void generic_visitor::visit(boot::program *program)
|
2024-12-23 13:54:11 +01:00
|
|
|
{
|
2025-02-03 23:04:00 +01:00
|
|
|
for (boot::constant_definition *const constant : program->constants)
|
2025-01-22 20:19:26 +01:00
|
|
|
{
|
2025-02-03 23:04:00 +01:00
|
|
|
constant->accept(this);
|
2025-01-22 20:19:26 +01:00
|
|
|
}
|
2025-02-03 23:04:00 +01:00
|
|
|
for (boot::type_definition *const type : program->types)
|
2025-01-11 13:32:37 +01:00
|
|
|
{
|
2025-02-03 23:04:00 +01:00
|
|
|
type->accept(this);
|
2025-01-11 13:32:37 +01:00
|
|
|
}
|
2025-02-03 23:04:00 +01:00
|
|
|
for (boot::variable_declaration *const variable : program->variables)
|
2025-02-02 08:22:40 +01:00
|
|
|
{
|
2025-02-03 23:04:00 +01:00
|
|
|
variable->accept(this);
|
|
|
|
}
|
|
|
|
for (boot::procedure_definition *const procedure : program->procedures)
|
|
|
|
{
|
|
|
|
procedure->accept(this);
|
2025-02-02 08:22:40 +01:00
|
|
|
}
|
2025-02-01 11:47:23 +01:00
|
|
|
std::array<tree, 2> parameter_types{
|
2024-12-23 13:54:11 +01:00
|
|
|
integer_type_node,
|
2024-12-28 14:33:35 +01:00
|
|
|
build_pointer_type(build_pointer_type(char_type_node))
|
2024-12-23 13:54:11 +01:00
|
|
|
};
|
2025-02-01 11:47:23 +01:00
|
|
|
tree declaration_type = build_function_type_array(integer_type_node, 2, parameter_types.data());
|
2025-02-09 23:49:57 +01:00
|
|
|
tree fndecl = build_fn_decl("main", declaration_type);
|
|
|
|
current_function_decl = fndecl;
|
2024-12-23 13:54:11 +01:00
|
|
|
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node);
|
2025-02-09 23:49:57 +01:00
|
|
|
DECL_CONTEXT(resdecl) = fndecl;
|
|
|
|
DECL_RESULT(fndecl) = resdecl;
|
2025-01-15 01:48:09 +01:00
|
|
|
|
2025-01-04 20:24:34 +01:00
|
|
|
enter_scope();
|
2024-12-23 13:54:11 +01:00
|
|
|
|
2025-02-01 11:47:23 +01:00
|
|
|
tree_chain argument_chain;
|
|
|
|
for (std::size_t i = 0; i < 2; ++i)
|
|
|
|
{
|
|
|
|
std::string argument_name = i == 0 ? "count" : "parameters";
|
|
|
|
tree argc_declaration_tree = build_decl(UNKNOWN_LOCATION, PARM_DECL,
|
|
|
|
get_identifier(argument_name.c_str()), parameter_types[i]);
|
2025-02-09 23:49:57 +01:00
|
|
|
DECL_CONTEXT(argc_declaration_tree) = fndecl;
|
2025-02-01 11:47:23 +01:00
|
|
|
DECL_ARG_TYPE(argc_declaration_tree) = parameter_types[i];
|
2025-02-04 13:28:09 +01:00
|
|
|
this->symbol_map->enter(argument_name, argc_declaration_tree);
|
2025-02-01 11:47:23 +01:00
|
|
|
argument_chain.append(argc_declaration_tree);
|
|
|
|
}
|
2025-02-09 23:49:57 +01:00
|
|
|
DECL_ARGUMENTS(fndecl) = argument_chain.head();
|
2025-02-01 11:47:23 +01:00
|
|
|
|
2025-02-03 23:04:00 +01:00
|
|
|
for (boot::statement *const body_statement : program->body)
|
2025-01-16 15:09:58 +01:00
|
|
|
{
|
|
|
|
body_statement->accept(this);
|
|
|
|
}
|
2025-02-09 23:49:57 +01:00
|
|
|
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-07 22:12:59 +01:00
|
|
|
this->scope.front().append_statement(return_stmt);
|
2025-01-04 20:24:34 +01:00
|
|
|
tree_symbol_mapping mapping = leave_scope();
|
2025-01-15 01:48:09 +01:00
|
|
|
|
2025-02-09 23:49:57 +01:00
|
|
|
BLOCK_SUPERCONTEXT(mapping.block()) = fndecl;
|
|
|
|
DECL_INITIAL(fndecl) = mapping.block();
|
|
|
|
DECL_SAVED_TREE(fndecl) = mapping.bind_expression();
|
2025-01-15 01:48:09 +01:00
|
|
|
|
2025-02-09 23:49:57 +01:00
|
|
|
DECL_EXTERNAL(fndecl) = 0;
|
|
|
|
DECL_PRESERVE_P(fndecl) = 1;
|
2025-01-15 01:48:09 +01:00
|
|
|
|
2025-02-09 23:49:57 +01:00
|
|
|
current_function_decl = NULL_TREE;
|
|
|
|
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-01-16 15:09:58 +01:00
|
|
|
parameter_types[i] = build_type(definition->parameters.at(i)->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());
|
2025-02-09 23:49:57 +01:00
|
|
|
tree fndecl = build_fn_decl(definition->identifier.c_str(), declaration_type);
|
|
|
|
this->symbol_map->enter(definition->identifier, fndecl);
|
2025-01-11 23:20:23 +01:00
|
|
|
|
2025-01-16 15:09:58 +01:00
|
|
|
if (definition->body() != nullptr)
|
|
|
|
{
|
2025-02-09 23:49:57 +01:00
|
|
|
current_function_decl = fndecl;
|
2025-01-18 21:30:11 +01:00
|
|
|
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, return_type);
|
2025-02-09 23:49:57 +01:00
|
|
|
DECL_CONTEXT(resdecl) = fndecl;
|
|
|
|
DECL_RESULT(fndecl) = resdecl;
|
2025-01-15 01:48:09 +01:00
|
|
|
|
2025-01-16 15:09:58 +01:00
|
|
|
enter_scope();
|
|
|
|
}
|
2025-02-01 11:47:23 +01:00
|
|
|
tree_chain argument_chain;
|
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(¶meter->position()), PARM_DECL,
|
2025-02-07 22:12:59 +01:00
|
|
|
get_identifier(parameter->identifier.c_str()), parameter_types[i]);
|
2025-02-09 23:49:57 +01:00
|
|
|
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-01-15 01:48:09 +01:00
|
|
|
argument_chain.append(declaration_tree);
|
|
|
|
}
|
2025-02-09 23:49:57 +01:00
|
|
|
DECL_ARGUMENTS(fndecl) = argument_chain.head();
|
|
|
|
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);
|
|
|
|
tree_symbol_mapping mapping = leave_scope();
|
2025-01-11 13:32:37 +01:00
|
|
|
|
2025-02-09 23:49:57 +01:00
|
|
|
BLOCK_SUPERCONTEXT(mapping.block()) = fndecl;
|
|
|
|
DECL_INITIAL(fndecl) = mapping.block();
|
|
|
|
DECL_SAVED_TREE(fndecl) = mapping.bind_expression();
|
2025-01-11 13:32:37 +01:00
|
|
|
|
2025-02-09 23:49:57 +01:00
|
|
|
DECL_EXTERNAL(fndecl) = 0;
|
|
|
|
DECL_PRESERVE_P(fndecl) = 1;
|
2025-01-11 13:32:37 +01:00
|
|
|
|
2025-02-09 23:49:57 +01:00
|
|
|
current_function_decl = NULL_TREE;
|
|
|
|
gimplify_function_tree(fndecl);
|
|
|
|
cgraph_node::finalize_function(fndecl, true);
|
2025-01-16 15:09:58 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2025-02-09 23:49:57 +01:00
|
|
|
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-07 22:12:59 +01:00
|
|
|
scope.emplace_front();
|
2025-01-31 09:46:17 +01:00
|
|
|
this->symbol_map = std::make_shared<boot::symbol_table<tree>>(this->symbol_map);
|
2025-01-04 20:24:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
tree_symbol_mapping generic_visitor::leave_scope()
|
|
|
|
{
|
2025-02-07 22:12:59 +01:00
|
|
|
tree new_block = build_block(this->scope.front().variables.head(),
|
|
|
|
this->scope.front().blocks.head(), NULL_TREE, NULL_TREE);
|
|
|
|
|
|
|
|
for (tree it = this->scope.front().blocks.head(); it != NULL_TREE; it = BLOCK_CHAIN(it))
|
|
|
|
{
|
|
|
|
BLOCK_SUPERCONTEXT(it) = new_block;
|
|
|
|
}
|
|
|
|
tree bind_expr = build3(BIND_EXPR, void_type_node, this->scope.front().variables.head(),
|
|
|
|
this->scope.front().chain_defer(), new_block);
|
2025-01-12 10:35:24 +01:00
|
|
|
this->symbol_map = this->symbol_map->scope();
|
2025-01-04 20:24:34 +01:00
|
|
|
|
2025-02-07 22:12:59 +01:00
|
|
|
scope.pop_front();
|
|
|
|
|
|
|
|
if (!scope.empty())
|
|
|
|
{
|
|
|
|
scope.front().blocks.append(new_block);
|
|
|
|
}
|
2025-01-04 20:24:34 +01:00
|
|
|
return tree_symbol_mapping{ bind_expr, new_block };
|
|
|
|
}
|
|
|
|
|
2025-01-31 09:46:17 +01:00
|
|
|
void generic_visitor::visit(boot::number_literal<std::int32_t> *literal)
|
2024-12-27 10:51:46 +01:00
|
|
|
{
|
2025-01-31 09:46:17 +01:00
|
|
|
auto symbol = this->symbol_map->lookup("Int");
|
|
|
|
|
2025-02-04 13:28:09 +01:00
|
|
|
this->current_expression = build_int_cst(symbol, literal->number());
|
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-01-31 09:46:17 +01:00
|
|
|
auto symbol = this->symbol_map->lookup("Word");
|
|
|
|
|
2025-02-04 13:28:09 +01:00
|
|
|
this->current_expression = build_int_cstu(symbol, literal->number());
|
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);
|
|
|
|
mpfr_set_d(number, literal->number(), 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);
|
|
|
|
}
|
|
|
|
|
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-01 11:47:23 +01:00
|
|
|
auto symbol = this->symbol_map->lookup("Bool");
|
|
|
|
|
2025-02-04 13:28:09 +01:00
|
|
|
this->current_expression = build_int_cst_type(symbol, boolean->number());
|
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-01 09:21:29 +01:00
|
|
|
auto symbol = this->symbol_map->lookup("Char");
|
|
|
|
|
2025-02-04 13:28:09 +01:00
|
|
|
this->current_expression = build_int_cstu(symbol, character->number());
|
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
|
|
|
{
|
|
|
|
this->current_expression = null_pointer_node;
|
|
|
|
}
|
|
|
|
|
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-07 22:12:59 +01:00
|
|
|
tree index_type = this->symbol_map->lookup("Word");
|
|
|
|
tree index_constant = build_int_cstu(index_type, string->number().size());
|
|
|
|
tree element_type = this->symbol_map->lookup("Char");
|
|
|
|
tree string_type = build_array_type(element_type, build_index_type(index_constant));
|
2025-02-08 23:02:27 +01:00
|
|
|
tree string_record = this->symbol_map->lookup("String");
|
2025-02-07 22:12:59 +01:00
|
|
|
|
|
|
|
tree string_literal = build_string(string->number().size(), string->number().c_str());
|
|
|
|
TREE_TYPE(string_literal) = string_type;
|
|
|
|
TREE_CONSTANT(string_literal) = 1;
|
|
|
|
TREE_READONLY(string_literal) = 1;
|
|
|
|
TREE_STATIC(string_literal) = 1;
|
|
|
|
|
2025-02-08 23:02:27 +01:00
|
|
|
string_type = TREE_TYPE(TREE_CHAIN(TYPE_FIELDS(string_record)));
|
2025-02-07 22:12:59 +01:00
|
|
|
string_literal = build4(ARRAY_REF, element_type, string_literal, integer_zero_node, NULL_TREE, NULL_TREE);
|
|
|
|
string_literal = build1(ADDR_EXPR, string_type, string_literal);
|
|
|
|
|
|
|
|
vec<constructor_elt, va_gc> *elms = NULL;
|
|
|
|
CONSTRUCTOR_APPEND_ELT(elms, TYPE_FIELDS(string_record), index_constant);
|
|
|
|
CONSTRUCTOR_APPEND_ELT(elms, TREE_CHAIN(TYPE_FIELDS(string_record)), string_literal);
|
|
|
|
|
|
|
|
this->current_expression = build_constructor(string_record, elms);
|
2025-01-03 22:18:35 +01:00
|
|
|
}
|
|
|
|
|
2025-02-02 08:22:40 +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
|
|
|
{
|
2025-02-02 08:22:40 +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
|
|
|
|
2025-02-02 08:22:40 +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-04 13:28:09 +01:00
|
|
|
expression, operator_code, left, right, this->symbol_map->lookup("Bool"));
|
2025-02-02 08:22:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
tree generic_visitor::build_logic_operation(boot::binary_expression *expression,
|
|
|
|
tree_code operator_code, tree left, tree right)
|
|
|
|
{
|
|
|
|
auto symbol = this->symbol_map->lookup("Bool");
|
|
|
|
|
2025-02-04 13:28:09 +01:00
|
|
|
return build_binary_operation(TREE_TYPE(left) == symbol,
|
|
|
|
expression, operator_code, left, right, symbol);
|
2025-02-02 08:22:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
tree generic_visitor::build_equality_operation(boot::binary_expression *expression,
|
|
|
|
tree_code operator_code, tree left, tree right)
|
|
|
|
{
|
|
|
|
return build_binary_operation(true, expression,
|
2025-02-04 13:28:09 +01:00
|
|
|
operator_code, left, right, this->symbol_map->lookup("Bool"));
|
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);
|
2025-02-02 08:22:40 +01:00
|
|
|
tree left = this->current_expression;
|
|
|
|
tree left_type = TREE_TYPE(left);
|
2024-12-27 10:51:46 +01:00
|
|
|
|
|
|
|
expression->rhs().accept(this);
|
2025-02-02 08:22:40 +01:00
|
|
|
tree right = this->current_expression;
|
|
|
|
tree right_type = TREE_TYPE(right);
|
2024-12-27 10:51:46 +01:00
|
|
|
|
2025-02-02 08:22:40 +01:00
|
|
|
location_t expression_location = get_location(&expression->position());
|
2024-12-27 10:51:46 +01:00
|
|
|
|
2025-02-05 13:24:50 +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))
|
2025-01-20 21:46:03 +01:00
|
|
|
{
|
2025-02-02 08:22:40 +01:00
|
|
|
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()));
|
|
|
|
}
|
2025-02-05 13:24:50 +01:00
|
|
|
else if (TREE_TYPE(this->current_expression) == ssizetype)
|
|
|
|
{
|
|
|
|
this->current_expression = fold_convert(this->symbol_map->lookup("Int"), this->current_expression);
|
|
|
|
}
|
2025-01-20 21:46:03 +01:00
|
|
|
return;
|
|
|
|
}
|
2025-02-08 23:02:27 +01:00
|
|
|
if (left_type != right_type && !are_compatible_pointers(left, right) && !are_compatible_pointers(right, left))
|
2024-12-31 18:10:34 +01:00
|
|
|
{
|
|
|
|
error_at(expression_location,
|
|
|
|
"invalid operands of type %s and %s for operator %s",
|
2025-02-08 23:02:27 +01:00
|
|
|
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:
|
2025-02-02 08:22:40 +01:00
|
|
|
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:
|
2025-02-02 08:22:40 +01:00
|
|
|
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:
|
2025-02-02 08:22:40 +01:00
|
|
|
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:
|
2025-02-02 08:22:40 +01:00
|
|
|
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:
|
2025-02-02 08:22:40 +01:00
|
|
|
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:
|
2025-02-02 08:22:40 +01:00
|
|
|
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:
|
2025-02-02 08:22:40 +01:00
|
|
|
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:
|
2025-02-02 08:22:40 +01:00
|
|
|
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:
|
2025-02-02 08:22:40 +01:00
|
|
|
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-02 08:22:40 +01:00
|
|
|
this->current_expression = build_logic_operation(expression, TRUTH_ANDIF_EXPR, 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-02 08:22:40 +01:00
|
|
|
this->current_expression = build_logic_operation(expression, TRUTH_ORIF_EXPR, 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-02 08:22:40 +01:00
|
|
|
this->current_expression = build_equality_operation(expression, EQ_EXPR, 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-02 08:22:40 +01:00
|
|
|
this->current_expression = build_equality_operation(expression, NE_EXPR, left, right);
|
2025-01-03 22:18:35 +01:00
|
|
|
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-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;
|
|
|
|
this->current_expression = build_fold_addr_expr_with_type_loc(get_location(&expression->position()),
|
|
|
|
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-01-13 11:55:19 +01:00
|
|
|
this->current_expression = build1_loc(get_location(&expression->position()), TRUTH_NOT_EXPR,
|
|
|
|
boolean_type_node, this->current_expression);
|
|
|
|
break;
|
2025-02-07 00:56:54 +01:00
|
|
|
case boot::unary_operator::minus:
|
|
|
|
this->current_expression = fold_build1(NEGATE_EXPR, TREE_TYPE(this->current_expression),
|
|
|
|
this->current_expression);
|
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
|
|
|
|
2025-01-12 10:35:24 +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-07 22:12:59 +01:00
|
|
|
if (!scope.empty())
|
|
|
|
{
|
|
|
|
auto declaration_statement = build1_loc(definition_location, DECL_EXPR,
|
|
|
|
void_type_node, definition_tree);
|
|
|
|
this->scope.front().append_statement(declaration_statement);
|
|
|
|
}
|
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
|
|
|
|
2025-01-12 10:35:24 +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;
|
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-01-31 09:46:17 +01:00
|
|
|
tree generic_visitor::build_type(boot::type_expression& type)
|
2024-12-27 23:38:25 +01:00
|
|
|
{
|
2025-01-31 09:46:17 +01:00
|
|
|
if (boot::basic_type_expression *basic_type = type.is_basic())
|
2024-12-31 18:10:34 +01:00
|
|
|
{
|
2025-02-04 13:28:09 +01:00
|
|
|
tree symbol = this->symbol_map->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-01-31 09:46:17 +01:00
|
|
|
else if (boot::array_type_expression *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-01-31 09:46:17 +01:00
|
|
|
else if (boot::pointer_type_expression *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-01-31 09:46:17 +01:00
|
|
|
else if (boot::record_type_expression *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);
|
|
|
|
tree_chain record_chain;
|
|
|
|
|
2025-01-17 10:11:40 +01:00
|
|
|
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-01-09 22:40:39 +01:00
|
|
|
record_chain.append(field_declaration);
|
|
|
|
}
|
|
|
|
TYPE_FIELDS(record_type_node) = record_chain.head();
|
|
|
|
layout_type(record_type_node);
|
|
|
|
|
|
|
|
return record_type_node;
|
|
|
|
}
|
2025-01-31 09:46:17 +01:00
|
|
|
else if (boot::union_type_expression *union_type = type.is_union())
|
2025-01-17 10:11:40 +01:00
|
|
|
{
|
|
|
|
std::set<std::string> field_names;
|
|
|
|
tree union_type_node = make_node(UNION_TYPE);
|
|
|
|
tree_chain union_chain;
|
|
|
|
|
|
|
|
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-01-17 10:11:40 +01:00
|
|
|
union_chain.append(field_declaration);
|
|
|
|
}
|
|
|
|
TYPE_FIELDS(union_type_node) = union_chain.head();
|
|
|
|
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
|
|
|
{
|
|
|
|
tree declaration_type = build_type(declaration->type());
|
2025-01-10 23:17:18 +01:00
|
|
|
gcc_assert(declaration_type != NULL_TREE);
|
2025-01-06 15:08:23 +01:00
|
|
|
|
2025-02-03 23:04:00 +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-03 23:04:00 +01:00
|
|
|
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-03 23:04:00 +01:00
|
|
|
}
|
2025-02-09 23:49:57 +01:00
|
|
|
else if (current_function_decl == NULL_TREE)
|
2025-02-03 23:04:00 +01:00
|
|
|
{
|
|
|
|
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
|
|
|
{
|
2025-02-09 23:49:57 +01:00
|
|
|
DECL_CONTEXT(declaration_tree) = current_function_decl;
|
2025-02-07 22:12:59 +01:00
|
|
|
this->scope.front().variables.append(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-07 22:12:59 +01:00
|
|
|
this->scope.front().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-01-12 10:35:24 +01:00
|
|
|
auto symbol = this->symbol_map->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;
|
|
|
|
|
|
|
|
expression->index().accept(this);
|
|
|
|
tree index = this->current_expression;
|
|
|
|
|
|
|
|
tree element_type = TREE_TYPE(TREE_TYPE(designator));
|
|
|
|
|
|
|
|
this->current_expression = build4_loc(get_location(&expression->position()),
|
|
|
|
ARRAY_REF, element_type, designator, index, NULL_TREE, NULL_TREE);
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
location_t expression_location = get_location(&expression->position());
|
|
|
|
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-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;
|
|
|
|
return;
|
|
|
|
}
|
2025-02-04 13:28:09 +01:00
|
|
|
if (TREE_TYPE(this->current_expression) == TREE_TYPE(lvalue)
|
2025-02-08 23:02:27 +01:00
|
|
|
|| are_compatible_pointers(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-07 22:12:59 +01:00
|
|
|
this->scope.front().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-01-07 14:37:30 +01:00
|
|
|
"cannot assign value of type %s to variable of type %s",
|
2025-02-08 23:02:27 +01:00
|
|
|
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-07 22:12:59 +01:00
|
|
|
tree_symbol_mapping mapping = leave_scope();
|
|
|
|
scope.front().append_statement(mapping.bind_expression());
|
2025-01-27 01:16:27 +01:00
|
|
|
}
|
|
|
|
tree endif_label_expr = build1(LABEL_EXPR, void_type_node, endif_label_decl);
|
2025-02-07 22:12:59 +01:00
|
|
|
this->scope.front().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
|
|
|
|
|
|
|
if (TREE_TYPE(this->current_expression) != boolean_type_node)
|
|
|
|
{
|
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",
|
2025-02-08 23:02:27 +01:00
|
|
|
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-07 22:12:59 +01:00
|
|
|
this->scope.front().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-07 22:12:59 +01:00
|
|
|
this->scope.front().append_statement(then_label_expr);
|
|
|
|
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-07 22:12:59 +01:00
|
|
|
tree_symbol_mapping mapping = leave_scope();
|
|
|
|
this->scope.front().append_statement(mapping.bind_expression());
|
|
|
|
this->scope.front().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-07 22:12:59 +01:00
|
|
|
this->scope.front().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);
|
|
|
|
|
2025-02-09 23:49:57 +01:00
|
|
|
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
|
|
|
statement->body().prerequisite().accept(this);
|
2024-12-28 14:33:35 +01:00
|
|
|
|
2024-12-31 18:10:34 +01:00
|
|
|
if (TREE_TYPE(this->current_expression) != boolean_type_node)
|
2024-12-28 14:33:35 +01:00
|
|
|
{
|
2025-01-25 19:50:36 +01:00
|
|
|
error_at(get_location(&statement->body().prerequisite().position()),
|
2024-12-28 14:33:35 +01:00
|
|
|
"expected expression of boolean type but its type is %s",
|
2025-02-08 23:02:27 +01:00
|
|
|
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-02-07 22:12:59 +01:00
|
|
|
enter_scope();
|
|
|
|
|
2025-01-25 19:50:36 +01:00
|
|
|
auto prerequisite_location = get_location(&statement->body().prerequisite().position());
|
|
|
|
auto body_location = get_location(&statement->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-07 22:12:59 +01:00
|
|
|
this->scope.front().append_statement(prerequisite_label_expr);
|
2024-12-28 14:33:35 +01:00
|
|
|
|
|
|
|
auto body_label_decl = build_label_decl("while_body", body_location);
|
|
|
|
auto end_label_decl = build_label_decl("end_while", UNKNOWN_LOCATION);
|
|
|
|
|
|
|
|
auto goto_body = build1_loc(prerequisite_location, GOTO_EXPR,
|
|
|
|
void_type_node, body_label_decl);
|
|
|
|
auto goto_end = build1_loc(prerequisite_location, GOTO_EXPR,
|
|
|
|
void_type_node, end_label_decl);
|
|
|
|
|
|
|
|
auto cond_expr = build3_loc(prerequisite_location, COND_EXPR,
|
|
|
|
void_type_node, this->current_expression, goto_body, goto_end);
|
2025-02-07 22:12:59 +01:00
|
|
|
this->scope.front().append_statement(cond_expr);
|
2024-12-28 14:33:35 +01:00
|
|
|
|
|
|
|
auto body_label_expr = build1_loc(body_location, LABEL_EXPR,
|
|
|
|
void_type_node, body_label_decl);
|
2025-02-07 22:12:59 +01:00
|
|
|
this->scope.front().append_statement(body_label_expr);
|
2024-12-28 14:33:35 +01:00
|
|
|
|
2025-01-25 19:50:36 +01:00
|
|
|
for (const auto body_statement : statement->body().statements)
|
|
|
|
{
|
|
|
|
body_statement->accept(this);
|
|
|
|
}
|
2025-02-07 22:12:59 +01:00
|
|
|
tree_symbol_mapping mapping = leave_scope();
|
|
|
|
this->scope.front().append_statement(mapping.bind_expression());
|
|
|
|
|
2024-12-28 14:33:35 +01:00
|
|
|
auto goto_check = build1(GOTO_EXPR, void_type_node, prerequisite_label_decl);
|
2025-02-07 22:12:59 +01:00
|
|
|
this->scope.front().append_statement(goto_check);
|
2024-12-28 14:33:35 +01:00
|
|
|
|
|
|
|
auto endif_label_expr = build1(LABEL_EXPR, void_type_node, end_label_decl);
|
2025-02-07 22:12:59 +01:00
|
|
|
this->scope.front().append_statement(endif_label_expr);
|
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-07 22:12:59 +01:00
|
|
|
this->scope.front().append_statement(this->current_expression);
|
|
|
|
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);
|
|
|
|
|
2025-02-09 23:49:57 +01:00
|
|
|
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-07 22:12:59 +01:00
|
|
|
this->scope.front().append_statement(return_stmt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void generic_visitor::visit(boot::defer_statement *statement)
|
|
|
|
{
|
|
|
|
enter_scope();
|
|
|
|
for (boot::statement *const body_statement : statement->statements)
|
|
|
|
{
|
|
|
|
body_statement->accept(this);
|
|
|
|
}
|
|
|
|
tree_symbol_mapping mapping = leave_scope();
|
|
|
|
scope.front().defer(mapping.bind_expression());
|
2025-01-18 21:30:11 +01:00
|
|
|
}
|
2024-12-23 13:54:11 +01:00
|
|
|
}
|
|
|
|
}
|