Implement case statements

This commit is contained in:
2025-04-10 23:55:56 +02:00
parent 18c4e79012
commit d01f36cc1a
8 changed files with 96 additions and 24 deletions

View File

@ -138,7 +138,7 @@ namespace elna::gcc
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",
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;
@ -182,7 +182,7 @@ namespace elna::gcc
if (is_void_type(record_fields))
{
error_at(argument_location, "too many arguments, expected %i, got %lu",
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;
@ -767,6 +767,11 @@ namespace elna::gcc
location_t definition_location = get_location(&definition->position());
definition->body().accept(this);
if (!extract_constant(definition_location))
{
this->current_expression = NULL_TREE;
return;
}
tree definition_tree = build_decl(definition_location, CONST_DECL,
get_identifier(definition->identifier.c_str()), TREE_TYPE(this->current_expression));
auto result = this->symbols->enter(definition->identifier, definition_tree);
@ -1419,9 +1424,18 @@ namespace elna::gcc
void generic_visitor::visit(boot::case_statement *statement)
{
statement->condition().accept(this);
tree condition_expression = this->current_expression;
tree end_label_declaration = create_artificial_label(UNKNOWN_LOCATION);
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 boot::switch_case& case_block : statement->cases)
@ -1429,7 +1443,17 @@ namespace elna::gcc
for (boot::literal_expression *const case_label : case_block.labels)
{
case_label->accept(this);
tree case_label_declaration = create_artificial_label(get_location(&case_label->position()));
location_t case_location = get_location(&case_label->position());
if (extract_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);
@ -1452,4 +1476,19 @@ namespace elna::gcc
this->current_expression = NULL_TREE;
}
bool generic_visitor::extract_constant(location_t expression_location)
{
if (TREE_CODE(this->current_expression) == CONST_DECL)
{
this->current_expression = DECL_INITIAL(this->current_expression);
}
if (TREE_CONSTANT(this->current_expression) == 0)
{
error_at(expression_location, "Expected a constant expression");
this->current_expression = error_mark_node;
return false;
}
return true;
}
}

View File

@ -37,14 +37,6 @@ namespace elna::gcc
return is_integral_type(type) || type == elna_float_type_node;
}
bool is_primitive_type(tree type)
{
gcc_assert(TYPE_P(type));
return TREE_CODE(type) == INTEGER_TYPE
|| type == elna_float_type_node
|| type == elna_bool_type_node;
}
bool is_array_type(tree type)
{
gcc_assert(TYPE_P(type));
@ -59,9 +51,7 @@ namespace elna::gcc
bool is_castable_type(tree type)
{
gcc_assert(TYPE_P(type));
auto code = TREE_CODE(type);
return is_primitive_type(type) || POINTER_TYPE_P(type) || code == ENUMERAL_TYPE;
return INTEGRAL_TYPE_P(type) || POINTER_TYPE_P(type) || TREE_CODE(type) == REAL_TYPE;
}
bool are_compatible_pointers(tree lhs_type, tree rhs)