Implement case statements
This commit is contained in:
@ -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;
|
||||
@ -632,7 +632,8 @@ namespace elna::gcc
|
||||
&& (expression->operation() == boot::binary_operator::sum
|
||||
|| expression->operation() == boot::binary_operator::subtraction))
|
||||
{
|
||||
this->current_expression = do_pointer_arithmetic(expression->operation(), left, right);
|
||||
this->current_expression = do_pointer_arithmetic(expression->operation(),
|
||||
left, right, expression_location);
|
||||
if (this->current_expression == error_mark_node)
|
||||
{
|
||||
error_at(expression_location,
|
||||
@ -767,6 +768,15 @@ namespace elna::gcc
|
||||
location_t definition_location = get_location(&definition->position());
|
||||
definition->body().accept(this);
|
||||
|
||||
if (extract_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.c_str()), TREE_TYPE(this->current_expression));
|
||||
auto result = this->symbols->enter(definition->identifier, definition_tree);
|
||||
@ -923,17 +933,16 @@ namespace elna::gcc
|
||||
expression->index().accept(this);
|
||||
if (!is_integral_type(TREE_TYPE(this->current_expression)))
|
||||
{
|
||||
error_at(location, "type '%s' cannot be used as index",
|
||||
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;
|
||||
}
|
||||
if (this->current_expression != elna_word_type_node)
|
||||
{
|
||||
this->current_expression = fold_convert(elna_word_type_node, this->current_expression);
|
||||
this->current_expression = convert(elna_word_type_node, this->current_expression);
|
||||
}
|
||||
tree offset = build2(MINUS_EXPR, elna_word_type_node,
|
||||
this->current_expression, size_one_node);
|
||||
tree offset = build2(MINUS_EXPR, elna_word_type_node, this->current_expression, size_one_node);
|
||||
|
||||
if (is_array_type(TREE_TYPE(designator)))
|
||||
{
|
||||
@ -947,14 +956,14 @@ namespace elna::gcc
|
||||
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(boot::binary_operator::sum, string_ptr, offset);
|
||||
tree target_pointer = do_pointer_arithmetic(boot::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'",
|
||||
error_at(location, "Indexing is not allowed on type '%s'",
|
||||
print_type(TREE_TYPE(designator)).c_str());
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
@ -1071,7 +1080,7 @@ namespace elna::gcc
|
||||
|
||||
if (is_array_type(aggregate_type) && expression->field() == "length")
|
||||
{
|
||||
this->current_expression = fold_convert(build_qualified_type(elna_word_type_node, TYPE_QUAL_CONST),
|
||||
this->current_expression = convert(build_qualified_type(elna_word_type_node, TYPE_QUAL_CONST),
|
||||
TYPE_MAX_VALUE(TYPE_DOMAIN(aggregate_type)));
|
||||
}
|
||||
else if (is_array_type(aggregate_type) && expression->field() == "ptr")
|
||||
@ -1419,17 +1428,36 @@ 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)
|
||||
{
|
||||
for (boot::literal_expression *const case_label : case_block.labels)
|
||||
for (boot::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 +1480,21 @@ namespace elna::gcc
|
||||
|
||||
this->current_expression = NULL_TREE;
|
||||
}
|
||||
|
||||
bool generic_visitor::extract_constant(location_t expression_location)
|
||||
{
|
||||
int code = TREE_CODE(this->current_expression);
|
||||
|
||||
if (code == CONST_DECL)
|
||||
{
|
||||
this->current_expression = DECL_INITIAL(this->current_expression);
|
||||
}
|
||||
else if (TREE_CODE_CLASS(code) != tcc_constant)
|
||||
{
|
||||
error_at(expression_location, "Expected a constant expression");
|
||||
this->current_expression = error_mark_node;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user