Implement enumeration type

This commit is contained in:
2025-04-04 22:48:12 +02:00
parent 50970f3289
commit ecf5559473
13 changed files with 444 additions and 357 deletions

View File

@ -78,7 +78,7 @@ namespace elna::gcc
{
return "()";
}
else if (is_pointer_type(unqualified_type))
else if (POINTER_TYPE_P(unqualified_type))
{
tree pointer_target_type = TREE_TYPE(type);
@ -129,6 +129,10 @@ namespace elna::gcc
{
return print_aggregate_name(unqualified_type, "union");
}
else if (TREE_CODE(type) == ENUMERAL_TYPE)
{
return print_aggregate_name(unqualified_type, "enumeration");
}
else
{
return "<<unknown-type>>";

View File

@ -57,6 +57,10 @@ namespace elna::gcc
{
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));
@ -227,7 +231,7 @@ namespace elna::gcc
build_global_pointer_type(expression_type), this->current_expression);
build_procedure_call(call_location, this->current_expression, call->arguments);
}
else if (is_pointer_type(expression_type) && TREE_CODE(TREE_TYPE(expression_type)) == FUNCTION_TYPE)
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);
}
@ -247,8 +251,7 @@ namespace elna::gcc
expression->value().accept(this);
tree cast_source = TREE_TYPE(this->current_expression);
if ((is_primitive_type(cast_target) || is_pointer_type(cast_target))
&& (is_primitive_type(cast_source) || is_pointer_type(cast_source)))
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);
@ -303,7 +306,8 @@ namespace elna::gcc
for (boot::constant_definition *const constant : program->constants)
{
constant->accept(this);
} for (boot::type_definition *const type : program->types)
}
for (boot::type_definition *const type : program->types)
{
type->accept(this);
}
@ -514,7 +518,7 @@ namespace elna::gcc
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)),
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);
}
@ -624,7 +628,7 @@ namespace elna::gcc
location_t expression_location = get_location(&expression->position());
if ((is_pointer_type(left_type) || is_pointer_type(right_type))
if ((POINTER_TYPE_P(left_type) || POINTER_TYPE_P(right_type))
&& (expression->operation() == boot::binary_operator::sum
|| expression->operation() == boot::binary_operator::subtraction))
{
@ -867,7 +871,7 @@ namespace elna::gcc
get_identifier(declaration->identifier.c_str()), this->current_expression);
bool result = this->symbols->enter(declaration->identifier, declaration_tree);
if (is_pointer_type(this->current_expression))
if (POINTER_TYPE_P(this->current_expression))
{
DECL_INITIAL(declaration_tree) = elna_pointer_nil_node;
}
@ -976,7 +980,7 @@ namespace elna::gcc
{
return false;
}
else if (!is_integral_type(this->current_expression))
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());
@ -1030,7 +1034,7 @@ namespace elna::gcc
return;
}
trait->parameters.front()->accept(this);
auto field_type = trait->parameters.at(1)->is_primitive();
auto field_type = trait->parameters.at(1)->is_named();
if (field_type == nullptr)
{
@ -1076,6 +1080,21 @@ namespace elna::gcc
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,
@ -1096,7 +1115,7 @@ namespace elna::gcc
location_t expression_location = get_location(&expression->position());
tree expression_type = TREE_TYPE(this->current_expression);
if (is_pointer_type(expression_type))
if (POINTER_TYPE_P(expression_type))
{
this->current_expression = build1_loc(expression_location, INDIRECT_REF,
TREE_TYPE(expression_type), this->current_expression);
@ -1285,7 +1304,7 @@ namespace elna::gcc
this->current_expression = NULL_TREE;
}
void generic_visitor::visit(boot::primitive_type_expression *type)
void generic_visitor::visit(boot::named_type_expression *type)
{
auto looked_up = this->unresolved.find(type->name);
tree symbol;
@ -1362,6 +1381,44 @@ namespace elna::gcc
this->current_expression = build_global_pointer_type(procedure_type_node);
}
void generic_visitor::visit(boot::enumeration_type_expression *type)
{
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);
}
void generic_visitor::visit(boot::defer_statement *statement)
{
enter_scope();

View File

@ -26,12 +26,6 @@ along with GCC; see the file COPYING3. If not see
namespace elna::gcc
{
bool is_pointer_type(tree type)
{
gcc_assert(TYPE_P(type));
return TREE_CODE(type) == POINTER_TYPE;
}
bool is_integral_type(tree type)
{
gcc_assert(TYPE_P(type));
@ -62,10 +56,12 @@ namespace elna::gcc
return type == NULL_TREE || type == void_type_node;
}
bool is_aggregate_type(tree type)
bool is_castable_type(tree type)
{
gcc_assert(TYPE_P(type));
return TREE_CODE(type) == RECORD_TYPE || TREE_CODE(type) == UNION_TYPE;
auto code = TREE_CODE(type);
return is_primitive_type(type) || POINTER_TYPE_P(type) || code == ENUMERAL_TYPE;
}
bool are_compatible_pointers(tree lhs_type, tree rhs)
@ -73,8 +69,8 @@ namespace elna::gcc
gcc_assert(TYPE_P(lhs_type));
tree rhs_type = TREE_TYPE(rhs);
return (is_pointer_type(lhs_type) && rhs == elna_pointer_nil_node)
|| (is_pointer_type(lhs_type) && lhs_type == rhs_type);
return (POINTER_TYPE_P(lhs_type) && rhs == elna_pointer_nil_node)
|| (POINTER_TYPE_P(lhs_type) && lhs_type == rhs_type);
}
tree prepare_rvalue(tree rvalue)
@ -152,12 +148,12 @@ namespace elna::gcc
tree pointer{ NULL_TREE };
tree offset{ NULL_TREE };
if (is_pointer_type(left_type) && is_integral_type(right_type))
if (POINTER_TYPE_P(left_type) && is_integral_type(right_type))
{
pointer = left;
offset = right;
}
else if (is_integral_type(left_type) && is_pointer_type(right_type))
else if (is_integral_type(left_type) && POINTER_TYPE_P(right_type))
{
pointer = right;
offset = left;
@ -175,7 +171,7 @@ namespace elna::gcc
}
else if (binary_operator == boot::binary_operator::subtraction)
{
if (is_pointer_type(left_type) && is_integral_type(right_type))
if (POINTER_TYPE_P(left_type) && is_integral_type(right_type))
{
tree pointer_type = left_type;
tree offset_type = right_type;
@ -187,7 +183,7 @@ namespace elna::gcc
convert_expression = fold_build1(NEGATE_EXPR, sizetype, convert_expression);
return fold_build2(POINTER_PLUS_EXPR, pointer_type, left, convert_expression);
}
else if (is_pointer_type(left_type) && is_pointer_type(right_type) && left_type == right_type)
else if (POINTER_TYPE_P(left_type) && POINTER_TYPE_P(right_type) && left_type == right_type)
{
return fold_build2(POINTER_DIFF_EXPR, ssizetype, left, right);
}
@ -224,9 +220,9 @@ namespace elna::gcc
}
tree field_declaration = TYPE_FIELDS(type);
if (!is_aggregate_type(type))
if (!RECORD_OR_UNION_TYPE_P(type))
{
error_at(expression_location, "type '%s' does not have a field named '%s'",
error_at(expression_location, "Type '%s' does not have a field named '%s'",
print_type(type).c_str(), field_name.c_str());
return error_mark_node;
}
@ -243,7 +239,7 @@ namespace elna::gcc
}
if (field_declaration == NULL_TREE)
{
error_at(expression_location, "record type does not have a field named '%s'", field_name.c_str());
error_at(expression_location, "Aggregate type does not have a field '%s'", field_name.c_str());
return error_mark_node;
}
return field_declaration;