Generate top-level code from symbol tables
This commit is contained in:
@ -16,13 +16,11 @@ along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <array>
|
||||
#include <set>
|
||||
|
||||
#include "elna/gcc/elna-generic.h"
|
||||
#include "elna/gcc/elna-diagnostic.h"
|
||||
#include "elna/gcc/elna1.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "elna/gcc/elna-builtins.h"
|
||||
|
||||
#include "ggc.h"
|
||||
#include "function.h"
|
||||
@ -38,91 +36,9 @@ along with GCC; see the file COPYING3. If not see
|
||||
|
||||
namespace elna::gcc
|
||||
{
|
||||
tree get_inner_alias(const boot::type& type, std::shared_ptr<symbol_table> symbols,
|
||||
std::unordered_map<std::string, tree>& unresolved, std::vector<std::string>& path)
|
||||
{
|
||||
if (auto reference = type.get<boot::primitive_type>())
|
||||
{
|
||||
auto looked_up = symbols->lookup(reference->identifier);
|
||||
if (looked_up != NULL_TREE)
|
||||
{
|
||||
return TREE_TYPE(looked_up);
|
||||
}
|
||||
}
|
||||
else if (auto reference = type.get<boot::record_type>())
|
||||
{
|
||||
return make_node(RECORD_TYPE);
|
||||
}
|
||||
else if (auto reference = type.get<boot::union_type>())
|
||||
{
|
||||
return make_node(UNION_TYPE);
|
||||
}
|
||||
else if (auto reference = type.get<boot::enumeration_type>())
|
||||
{
|
||||
return make_node(ENUMERAL_TYPE);
|
||||
}
|
||||
else if (auto reference = type.get<boot::pointer_type>())
|
||||
{
|
||||
return build_global_pointer_type(get_inner_alias(reference->base, symbols, unresolved, path));
|
||||
}
|
||||
else if (auto reference = type.get<boot::array_type>())
|
||||
{
|
||||
tree lower_bound = build_int_cst_type(integer_type_node, 0);
|
||||
tree upper_bound = build_int_cst_type(integer_type_node, reference->size);
|
||||
tree range_type = build_range_type(integer_type_node, lower_bound, upper_bound);
|
||||
|
||||
return build_array_type(get_inner_alias(reference->base, symbols, unresolved, path), range_type);
|
||||
}
|
||||
else if (auto reference = type.get<boot::alias_type>())
|
||||
{
|
||||
return handle_symbol(reference->name, reference, symbols, unresolved, path);
|
||||
}
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
tree handle_symbol(const std::string& symbol_name, std::shared_ptr<boot::alias_type> reference,
|
||||
std::shared_ptr<symbol_table> symbols, std::unordered_map<std::string, tree>& unresolved,
|
||||
std::vector<std::string>& path)
|
||||
{
|
||||
path.push_back(symbol_name);
|
||||
std::vector<std::string>::const_iterator head_peace = std::cbegin(path);
|
||||
|
||||
if (std::find(std::next(head_peace), std::cend(path), *head_peace) != std::cend(path))
|
||||
{
|
||||
return error_mark_node;
|
||||
}
|
||||
auto looked_up = get_inner_alias(reference->reference, symbols, unresolved, path);
|
||||
|
||||
unresolved.insert({ symbol_name, looked_up });
|
||||
|
||||
return looked_up;
|
||||
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, tree> do_semantic_analysis(std::shared_ptr<boot::symbol_table> info_table,
|
||||
std::shared_ptr<symbol_table> symbols)
|
||||
{
|
||||
std::unordered_map<std::string, tree> unresolved;
|
||||
|
||||
for (auto& [symbol_name, symbol_info] : *info_table)
|
||||
{
|
||||
std::vector<std::string> type_path;
|
||||
|
||||
// The top level symbol table has basic (builtin) types in it which are not aliases.
|
||||
if (auto type_info = symbol_info->is_type())
|
||||
{
|
||||
if (auto alias_type = type_info->symbol.get<boot::alias_type>())
|
||||
{
|
||||
handle_symbol(symbol_name, alias_type, symbols, unresolved, type_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
return unresolved;
|
||||
}
|
||||
|
||||
generic_visitor::generic_visitor(std::shared_ptr<symbol_table> symbol_table,
|
||||
std::unordered_map<std::string, tree>&& unresolved)
|
||||
: symbols(symbol_table), unresolved(std::move(unresolved))
|
||||
std::shared_ptr<boot::symbol_table> info_table)
|
||||
: symbols(symbol_table), info_table(info_table)
|
||||
{
|
||||
}
|
||||
|
||||
@ -301,8 +217,8 @@ namespace elna::gcc
|
||||
|
||||
void generic_visitor::visit(boot::cast_expression *expression)
|
||||
{
|
||||
expression->target().accept(this);
|
||||
tree cast_target = this->current_expression;
|
||||
std::vector<std::string> path;
|
||||
tree cast_target = get_inner_alias(expression->expression_type, this->symbols->scope(), path);
|
||||
|
||||
expression->value().accept(this);
|
||||
tree cast_source = TREE_TYPE(this->current_expression);
|
||||
@ -320,43 +236,6 @@ namespace elna::gcc
|
||||
}
|
||||
}
|
||||
|
||||
void generic_visitor::declare_procedure(boot::procedure_declaration *const definition)
|
||||
{
|
||||
tree declaration_type = build_procedure_type(definition->heading());
|
||||
tree fndecl = build_fn_decl(definition->identifier.identifier.c_str(), declaration_type);
|
||||
this->symbols->enter(definition->identifier.identifier, fndecl);
|
||||
|
||||
if (definition->heading().return_type.no_return)
|
||||
{
|
||||
TREE_THIS_VOLATILE(fndecl) = 1;
|
||||
}
|
||||
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, TREE_TYPE(declaration_type));
|
||||
DECL_CONTEXT(resdecl) = fndecl;
|
||||
DECL_RESULT(fndecl) = resdecl;
|
||||
|
||||
tree argument_chain = NULL_TREE;
|
||||
function_args_iterator parameter_type;
|
||||
function_args_iter_init(¶meter_type, declaration_type);
|
||||
|
||||
std::vector<std::string>::const_iterator parameter_name = definition->parameter_names.cbegin();
|
||||
|
||||
for (boot::type_expression *parameter : definition->heading().parameters)
|
||||
{
|
||||
tree declaration_tree = build_decl(get_location(¶meter->position()), PARM_DECL,
|
||||
get_identifier(parameter_name->c_str()), function_args_iter_cond(¶meter_type));
|
||||
DECL_CONTEXT(declaration_tree) = fndecl;
|
||||
DECL_ARG_TYPE(declaration_tree) = function_args_iter_cond(¶meter_type);
|
||||
|
||||
argument_chain = chainon(argument_chain, declaration_tree);
|
||||
function_args_iter_next(¶meter_type);
|
||||
++parameter_name;
|
||||
}
|
||||
DECL_ARGUMENTS(fndecl) = argument_chain;
|
||||
TREE_PUBLIC(fndecl) = definition->identifier.exported;
|
||||
TREE_ADDRESSABLE(fndecl) = 1;
|
||||
DECL_EXTERNAL(fndecl) = !definition->body.has_value();
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::program *program)
|
||||
{
|
||||
visit(static_cast<boot::unit *>(program));
|
||||
@ -424,10 +303,6 @@ namespace elna::gcc
|
||||
variable->accept(this);
|
||||
}
|
||||
for (boot::procedure_declaration *const procedure : unit->procedures)
|
||||
{
|
||||
declare_procedure(procedure);
|
||||
}
|
||||
for (boot::procedure_declaration *const procedure : unit->procedures)
|
||||
{
|
||||
procedure->accept(this);
|
||||
}
|
||||
@ -435,16 +310,19 @@ namespace elna::gcc
|
||||
|
||||
void generic_visitor::visit(boot::procedure_declaration *definition)
|
||||
{
|
||||
tree fndecl = this->symbols->lookup(definition->identifier.identifier);
|
||||
TREE_PUBLIC(fndecl) = definition->identifier.exported;
|
||||
|
||||
if (!definition->body.has_value())
|
||||
{
|
||||
return;
|
||||
}
|
||||
tree fndecl = this->symbols->lookup(definition->identifier.identifier);
|
||||
|
||||
push_struct_function(fndecl, false);
|
||||
DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc<language_function>();
|
||||
|
||||
enter_scope();
|
||||
this->info_table = this->info_table->lookup(definition->identifier.identifier)->is_procedure()->symbols;
|
||||
|
||||
tree argument_chain = DECL_ARGUMENTS(fndecl);
|
||||
for (; argument_chain != NULL_TREE; argument_chain = TREE_CHAIN(argument_chain))
|
||||
@ -462,6 +340,7 @@ namespace elna::gcc
|
||||
visit_statements(definition->body.value().body());
|
||||
|
||||
tree mapping = leave_scope();
|
||||
this->info_table = this->info_table->scope();
|
||||
|
||||
BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl;
|
||||
DECL_INITIAL(fndecl) = BIND_EXPR_BLOCK(mapping);
|
||||
@ -860,85 +739,17 @@ namespace elna::gcc
|
||||
this->current_expression = NULL_TREE;
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::type_declaration *definition)
|
||||
void generic_visitor::visit(boot::type_declaration *declaration)
|
||||
{
|
||||
location_t definition_location = get_location(&definition->position());
|
||||
this->current_expression = this->unresolved.at(definition->identifier.identifier);
|
||||
definition->body().accept(this);
|
||||
|
||||
tree definition_tree = build_decl(definition_location, TYPE_DECL,
|
||||
get_identifier(definition->identifier.identifier.c_str()), this->current_expression);
|
||||
|
||||
TREE_PUBLIC(definition_tree) = definition->identifier.exported;
|
||||
if (is_unique_type(this->current_expression))
|
||||
{
|
||||
TYPE_NAME(this->current_expression) = DECL_NAME(definition_tree);
|
||||
TYPE_STUB_DECL(this->current_expression) = definition_tree;
|
||||
}
|
||||
else
|
||||
{
|
||||
TYPE_NAME(this->current_expression) = definition_tree;
|
||||
}
|
||||
auto result = this->symbols->enter(definition->identifier.identifier, definition_tree);
|
||||
gcc_assert(result);
|
||||
|
||||
this->current_expression = NULL_TREE;
|
||||
}
|
||||
|
||||
tree generic_visitor::build_procedure_type(boot::procedure_type_expression& type)
|
||||
{
|
||||
std::vector<tree> parameter_types(type.parameters.size());
|
||||
|
||||
for (std::size_t i = 0; i < type.parameters.size(); ++i)
|
||||
{
|
||||
type.parameters.at(i)->accept(this);
|
||||
parameter_types[i] = this->current_expression;
|
||||
}
|
||||
tree return_type = void_type_node;
|
||||
|
||||
if (type.return_type.proper_type != nullptr)
|
||||
{
|
||||
type.return_type.proper_type->accept(this);
|
||||
return_type = this->current_expression;
|
||||
}
|
||||
this->current_expression = NULL_TREE;
|
||||
|
||||
return build_function_type_array(return_type, type.parameters.size(), parameter_types.data());
|
||||
}
|
||||
|
||||
void generic_visitor::build_composite_type(const std::vector<boot::field_declaration>& fields,
|
||||
tree composite_type_node)
|
||||
{
|
||||
std::set<std::string> field_names;
|
||||
|
||||
for (auto& field : fields)
|
||||
{
|
||||
if (field_names.find(field.first) != field_names.cend())
|
||||
{
|
||||
error_at(get_location(&field.second->position()), "repeated field name");
|
||||
this->current_expression = error_mark_node;
|
||||
return;
|
||||
}
|
||||
field_names.insert(field.first);
|
||||
|
||||
field.second->accept(this);
|
||||
if (this->current_expression == NULL_TREE || this->current_expression == error_mark_node)
|
||||
{
|
||||
return;
|
||||
}
|
||||
tree field_declaration = build_field(get_location(&field.second->position()),
|
||||
composite_type_node, field.first, this->current_expression);
|
||||
TYPE_FIELDS(composite_type_node) = chainon(TYPE_FIELDS(composite_type_node), field_declaration);
|
||||
this->current_expression = NULL_TREE;
|
||||
}
|
||||
layout_type(composite_type_node);
|
||||
|
||||
this->current_expression = composite_type_node;
|
||||
TREE_PUBLIC(this->symbols->lookup(declaration->identifier.identifier)) = declaration->identifier.exported;
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::variable_declaration *declaration)
|
||||
{
|
||||
declaration->variable_type().accept(this);
|
||||
std::vector<std::string> path;
|
||||
this->current_expression = get_inner_alias(
|
||||
this->info_table->lookup(declaration->identifier.identifier)->is_variable()->symbol,
|
||||
this->symbols->scope(), path);
|
||||
|
||||
location_t declaration_location = get_location(&declaration->position());
|
||||
tree declaration_tree = build_decl(declaration_location, VAR_DECL,
|
||||
@ -949,6 +760,7 @@ namespace elna::gcc
|
||||
{
|
||||
DECL_INITIAL(declaration_tree) = elna_pointer_nil_node;
|
||||
}
|
||||
TREE_PUBLIC(declaration_tree) = declaration->identifier.exported;
|
||||
this->current_expression = NULL_TREE;
|
||||
if (!result)
|
||||
{
|
||||
@ -1042,7 +854,8 @@ namespace elna::gcc
|
||||
this->current_expression = error_mark_node;
|
||||
return false;
|
||||
}
|
||||
trait->parameters.front()->accept(this);
|
||||
std::vector<std::string> path;
|
||||
this->current_expression = get_inner_alias(trait->types.front(), this->symbols, path);
|
||||
|
||||
return this->current_expression != error_mark_node;
|
||||
}
|
||||
@ -1106,7 +919,8 @@ namespace elna::gcc
|
||||
this->current_expression = error_mark_node;
|
||||
return;
|
||||
}
|
||||
trait->parameters.front()->accept(this);
|
||||
std::vector<std::string> path;
|
||||
this->current_expression = get_inner_alias(trait->types.front(), this->symbols, path);
|
||||
auto field_type = trait->parameters.at(1)->is_named();
|
||||
|
||||
if (field_type == nullptr)
|
||||
@ -1383,45 +1197,12 @@ namespace elna::gcc
|
||||
|
||||
void generic_visitor::visit(boot::named_type_expression *type)
|
||||
{
|
||||
auto looked_up = this->unresolved.find(type->name);
|
||||
tree symbol;
|
||||
|
||||
if (looked_up == this->unresolved.cend())
|
||||
{
|
||||
symbol = this->symbols->lookup(type->name);
|
||||
if (symbol != NULL_TREE)
|
||||
{
|
||||
symbol = TREE_TYPE(symbol);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
symbol = looked_up->second;
|
||||
}
|
||||
if (symbol == NULL_TREE || !TYPE_P(symbol))
|
||||
{
|
||||
error_at(get_location(&type->position()), "Type '%s' not declared", type->name.c_str());
|
||||
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->current_expression = symbol;
|
||||
}
|
||||
this->current_expression = TREE_TYPE(this->symbols->lookup(type->name));
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::array_type_expression *type)
|
||||
void generic_visitor::visit(boot::array_type_expression *)
|
||||
{
|
||||
tree lower_bound = build_int_cst_type(integer_type_node, 0);
|
||||
tree upper_bound = build_int_cst_type(integer_type_node, type->size);
|
||||
type->base().accept(this);
|
||||
|
||||
if (this->current_expression != NULL_TREE && this->current_expression != error_mark_node)
|
||||
{
|
||||
tree range_type = build_range_type(integer_type_node, lower_bound, upper_bound);
|
||||
|
||||
this->current_expression = build_array_type(this->current_expression, range_type);
|
||||
}
|
||||
gcc_unreachable();
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::pointer_type_expression *type)
|
||||
@ -1434,66 +1215,24 @@ namespace elna::gcc
|
||||
}
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::record_type_expression *type)
|
||||
void generic_visitor::visit(boot::record_type_expression *)
|
||||
{
|
||||
tree composite_type_node = this->current_expression == NULL_TREE
|
||||
? make_node(RECORD_TYPE)
|
||||
: this->current_expression;
|
||||
|
||||
build_composite_type(type->fields, composite_type_node);
|
||||
gcc_unreachable();
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::union_type_expression *type)
|
||||
void generic_visitor::visit(boot::union_type_expression *)
|
||||
{
|
||||
tree composite_type_node = this->current_expression == NULL_TREE
|
||||
? make_node(UNION_TYPE)
|
||||
: this->current_expression;
|
||||
|
||||
build_composite_type(type->fields, composite_type_node);
|
||||
gcc_unreachable();
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::procedure_type_expression *type)
|
||||
void generic_visitor::visit(boot::procedure_type_expression *)
|
||||
{
|
||||
tree procedure_type_node = build_procedure_type(*type);
|
||||
this->current_expression = build_global_pointer_type(procedure_type_node);
|
||||
gcc_unreachable();
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::enumeration_type_expression *type)
|
||||
void generic_visitor::visit(boot::enumeration_type_expression *)
|
||||
{
|
||||
tree composite_type_node = this->current_expression == NULL_TREE
|
||||
? make_node(ENUMERAL_TYPE)
|
||||
: this->current_expression;
|
||||
location_t enum_location = get_location(&type->position());
|
||||
const tree base_type = integer_type_node;
|
||||
|
||||
TREE_TYPE(composite_type_node) = base_type;
|
||||
ENUM_IS_SCOPED(composite_type_node) = 1;
|
||||
|
||||
tree *pp = &TYPE_VALUES(composite_type_node);
|
||||
std::size_t order{ 1 };
|
||||
|
||||
for (const std::string& member : type->members)
|
||||
{
|
||||
tree member_name = get_identifier(member.c_str());
|
||||
tree member_declaration = build_decl(enum_location, CONST_DECL, member_name, composite_type_node);
|
||||
|
||||
DECL_CONTEXT(member_declaration) = composite_type_node;
|
||||
DECL_INITIAL(member_declaration) = build_int_cst_type(composite_type_node, order++);
|
||||
TREE_CONSTANT(member_declaration) = 1;
|
||||
TREE_READONLY(member_declaration) = 1;
|
||||
|
||||
TYPE_MAX_VALUE(composite_type_node) = DECL_INITIAL(member_declaration);
|
||||
|
||||
*pp = build_tree_list(member_name, member_declaration);
|
||||
pp = &TREE_CHAIN(*pp);
|
||||
}
|
||||
TYPE_MIN_VALUE(composite_type_node) = DECL_INITIAL(TREE_VALUE(TYPE_VALUES(composite_type_node)));
|
||||
TYPE_UNSIGNED(composite_type_node) = TYPE_UNSIGNED(base_type);
|
||||
SET_TYPE_ALIGN(composite_type_node, TYPE_ALIGN(base_type));
|
||||
TYPE_SIZE(composite_type_node) = NULL_TREE;
|
||||
TYPE_PRECISION(composite_type_node) = TYPE_PRECISION(base_type);
|
||||
|
||||
layout_type(composite_type_node);
|
||||
gcc_unreachable();
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::defer_statement *statement)
|
||||
|
Reference in New Issue
Block a user