aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-07-15 23:19:58 +0200
committerEugen Wissner <belka@caraus.de>2026-07-15 23:50:57 +0200
commitd0a666507a6f11b65170c257fd483613f462f3f2 (patch)
tree1a23edf414234defbb1b6a36aadcf3e7795e24dc
parente7265af15f77abf60a899b3d53a59652b5ca71ea (diff)
downloadelna-d0a666507a6f11b65170c257fd483613f462f3f2.tar.gz
Use build3(COND_EXPR) for conditionals
-rw-r--r--boot/semantic.cc31
-rw-r--r--gcc/gcc/elna-builtins.cc6
-rw-r--r--gcc/gcc/elna-generic.cc150
-rw-r--r--gcc/gcc/elna-tree.cc7
-rw-r--r--include/elna/boot/semantic.h15
-rw-r--r--include/elna/gcc/elna-generic.h4
-rw-r--r--include/elna/gcc/elna-tree.h1
7 files changed, 124 insertions, 90 deletions
diff --git a/boot/semantic.cc b/boot/semantic.cc
index 031adfc..9137053 100644
--- a/boot/semantic.cc
+++ b/boot/semantic.cc
@@ -206,6 +206,18 @@ namespace elna::boot
}
}
+ unsupported_trait_type_error::unsupported_trait_type_error(const identifier& trait,
+ type actual)
+ : error(trait.position()), trait_name(trait.name()), actual(actual)
+ {
+ }
+
+ std::string unsupported_trait_type_error::what() const
+ {
+ return "Type '" + actual.to_string()
+ + "' does not support trait '#" + trait_name + "'";
+ }
+
type_analysis_visitor::type_analysis_visitor(symbol_bag bag)
: error_container(), bag(bag)
{
@@ -917,6 +929,25 @@ namespace elna::boot
else if (trait->name == "min" || trait->name == "max")
{
trait->type_decoration = trait->types.empty() ? type() : trait->types.front();
+
+ if (!trait->type_decoration.empty())
+ {
+ type resolved = inner_aliased_type(trait->type_decoration);
+ bool is_enum = resolved.get<enumeration_type>() != nullptr;
+ bool is_integral = false;
+
+ if (auto prim = resolved.get<primitive_type>())
+ {
+ is_integral = prim->identifier == "Int" || prim->identifier == "Word"
+ || prim->identifier == "Bool" || prim->identifier == "Char";
+ }
+ if (!is_enum && !is_integral)
+ {
+ add_error<unsupported_trait_type_error>(trait->name,
+ trait->type_decoration);
+ trait->type_decoration = type();
+ }
+ }
}
else
{
diff --git a/gcc/gcc/elna-builtins.cc b/gcc/gcc/elna-builtins.cc
index 42ddcfe..9e331cf 100644
--- a/gcc/gcc/elna-builtins.cc
+++ b/gcc/gcc/elna-builtins.cc
@@ -40,7 +40,7 @@ namespace elna::gcc
elna_pointer_nil_node = null_pointer_node;
elna_string_type_node = make_node(RECORD_TYPE);
- tree string_ptr_type = build_pointer_type_for_mode(elna_char_type_node, VOIDmode, true);
+ tree string_ptr_type = build_pointer_type(elna_char_type_node);
elna_string_length_field_node = build_field(UNKNOWN_LOCATION,
elna_string_type_node, "length", build_qualified_type(elna_word_type_node, TYPE_QUAL_CONST));
@@ -146,7 +146,7 @@ namespace elna::gcc
}
else if (auto reference = type.get<boot::pointer_type>())
{
- return build_global_pointer_type(get_inner_alias(reference->base, symbols));
+ return build_pointer_type(get_inner_alias(reference->base, symbols));
}
else if (auto reference = type.get<boot::array_type>())
{
@@ -158,7 +158,7 @@ namespace elna::gcc
{
auto procedure = build_procedure_type(*reference, symbols);
- return build_global_pointer_type(procedure);
+ return build_pointer_type(procedure);
}
else if (auto reference = type.get<boot::alias_type>())
{
diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc
index aace38b..4067bb6 100644
--- a/gcc/gcc/elna-generic.cc
+++ b/gcc/gcc/elna-generic.cc
@@ -143,7 +143,7 @@ namespace elna::gcc
else if (TREE_CODE(expression_type) == FUNCTION_TYPE)
{
this->current_expression = build1(ADDR_EXPR,
- build_global_pointer_type(expression_type), this->current_expression);
+ build_pointer_type(expression_type), this->current_expression);
build_procedure_call(call_location, this->current_expression, call->arguments);
}
else if (POINTER_TYPE_P(expression_type) && TREE_CODE(TREE_TYPE(expression_type)) == FUNCTION_TYPE)
@@ -167,7 +167,7 @@ namespace elna::gcc
if (is_castable_type(cast_target) && (is_castable_type(cast_source)))
{
- this->current_expression = build1_loc(get_location(&expression->position()), CONVERT_EXPR,
+ this->current_expression = fold_convert_loc(get_location(&expression->position()),
cast_target, this->current_expression);
}
else
@@ -244,7 +244,7 @@ namespace elna::gcc
{
tree declaration_type = build_function_type_list(elna_int_type_node,
elna_int_type_node,
- build_global_pointer_type(build_global_pointer_type(elna_char_type_node)),
+ build_pointer_type(build_pointer_type(elna_char_type_node)),
NULL_TREE);
tree fndecl = build_fn_decl("main", declaration_type);
@@ -659,39 +659,48 @@ namespace elna::gcc
TREE_ADDRESSABLE(this->current_expression) = 1;
this->current_expression = build_fold_addr_expr_with_type_loc(location,
this->current_expression,
- build_global_pointer_type(TREE_TYPE(this->current_expression)));
+ build_pointer_type(TREE_TYPE(this->current_expression)));
TREE_NO_TRAMPOLINE(this->current_expression) = 1;
break;
case boot::unary_operator::negation:
- if (TREE_TYPE(this->current_expression) == elna_bool_type_node)
+ {
+ tree operand_type = TREE_TYPE(this->current_expression);
+
+ if (operand_type == elna_bool_type_node)
{
this->current_expression = build1_loc(location, TRUTH_NOT_EXPR,
boolean_type_node, this->current_expression);
}
- else if (is_integral_type(TREE_TYPE(this->current_expression)))
+ else if (is_integral_type(operand_type))
{
this->current_expression = build1_loc(location, BIT_NOT_EXPR,
- TREE_TYPE(this->current_expression), this->current_expression);
+ operand_type, this->current_expression);
}
else
{
error_at(location, "type '%s' cannot be negated",
- print_type(TREE_TYPE(this->current_expression)).c_str());
+ print_type(operand_type).c_str());
this->current_expression = error_mark_node;
}
break;
+ }
case boot::unary_operator::minus:
- if (is_integral_type(TREE_TYPE(this->current_expression)))
+ {
+ tree operand_type = TREE_TYPE(this->current_expression);
+
+ if (is_integral_type(operand_type))
{
- this->current_expression = fold_build1(NEGATE_EXPR, TREE_TYPE(this->current_expression),
- this->current_expression);
+ this->current_expression = fold_build1_loc(location, NEGATE_EXPR,
+ operand_type, this->current_expression);
}
else
{
error_at(location, "type '%s' cannot be negated",
- print_type(TREE_TYPE(this->current_expression)).c_str());
+ print_type(operand_type).c_str());
this->current_expression = error_mark_node;
}
+ break;
+ }
}
}
@@ -818,8 +827,7 @@ namespace elna::gcc
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);
+ this->current_expression = build_simple_mem_ref_loc(location, target_pointer);
}
else
{
@@ -843,22 +851,6 @@ namespace elna::gcc
return this->current_expression != error_mark_node;
}
- bool generic_visitor::expect_trait_for_integral_type(boot::traits_expression *trait)
- {
- if (!expect_trait_type_only(trait))
- {
- return false;
- }
- 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.name().c_str());
- this->current_expression = error_mark_node;
- return false;
- }
- return true;
- }
-
void generic_visitor::visit(boot::traits_expression *trait)
{
location_t trait_location = get_location(&trait->position());
@@ -867,7 +859,7 @@ namespace elna::gcc
{
if (expect_trait_type_only(trait))
{
- this->current_expression = build1_loc(trait_location, CONVERT_EXPR, elna_word_type_node,
+ this->current_expression = fold_convert_loc(trait_location, elna_word_type_node,
size_in_bytes(this->current_expression));
}
}
@@ -881,14 +873,14 @@ namespace elna::gcc
}
else if (trait->name == "min")
{
- if (expect_trait_for_integral_type(trait))
+ if (expect_trait_type_only(trait))
{
this->current_expression = TYPE_MIN_VALUE(this->current_expression);
}
}
else if (trait->name == "max")
{
- if (expect_trait_for_integral_type(trait))
+ if (expect_trait_type_only(trait))
{
this->current_expression = TYPE_MAX_VALUE(this->current_expression);
}
@@ -917,7 +909,7 @@ namespace elna::gcc
if (field_declaration != error_mark_node)
{
- this->current_expression = build1(CONVERT_EXPR, elna_word_type_node,
+ this->current_expression = fold_convert_loc(trait_location, elna_word_type_node,
byte_position(field_declaration));
}
else
@@ -944,7 +936,7 @@ namespace elna::gcc
}
else if (TREE_CODE(aggregate_type) == ARRAY_TYPE && expression->field() == "ptr")
{
- tree ptr_type = build_global_pointer_type(TREE_TYPE(aggregate_type));
+ tree ptr_type = build_pointer_type(TREE_TYPE(aggregate_type));
this->current_expression = build1(ADDR_EXPR,
build_qualified_type(ptr_type, TYPE_QUAL_CONST), this->current_expression);
}
@@ -984,8 +976,8 @@ namespace elna::gcc
if (POINTER_TYPE_P(expression_type))
{
- this->current_expression = build1_loc(expression_location, INDIRECT_REF,
- TREE_TYPE(expression_type), this->current_expression);
+ this->current_expression = build_simple_mem_ref_loc(expression_location,
+ this->current_expression);
}
else
{
@@ -1026,28 +1018,31 @@ namespace elna::gcc
void generic_visitor::visit(boot::if_statement *statement)
{
- tree endif_label_decl = create_artificial_label(UNKNOWN_LOCATION);
- tree goto_endif = build1(GOTO_EXPR, void_type_node, endif_label_decl);
+ tree result = NULL_TREE;
- make_if_branch(statement->branch(), goto_endif);
-
- for (const auto branch : statement->branches)
- {
- make_if_branch(*branch, goto_endif);
- }
if (statement->alternative != nullptr)
{
enter_scope();
visit_statements(*statement->alternative);
- tree mapping = leave_scope();
- append_statement(mapping);
+ result = leave_scope();
+ }
+
+ auto& branches = statement->branches;
+ for (auto it = branches.rbegin(); it != branches.rend(); ++it)
+ {
+ result = make_if_branch(**it, result);
+ }
+ result = make_if_branch(statement->branch(), result);
+
+ if (result != error_mark_node)
+ {
+ append_statement(result);
}
- tree endif_label_expr = build1(LABEL_EXPR, void_type_node, endif_label_decl);
- append_statement(endif_label_expr);
this->current_expression = NULL_TREE;
}
- void generic_visitor::make_if_branch(boot::conditional_statements& branch, tree goto_endif)
+ tree generic_visitor::make_if_branch(boot::conditional_statements& branch, tree next,
+ tree goto_append)
{
branch.prerequisite().accept(this);
@@ -1057,28 +1052,19 @@ namespace elna::gcc
"Expected expression of boolean type but its type is %s",
print_type(TREE_TYPE(this->current_expression)).c_str());
this->current_expression = error_mark_node;
- return;
+ return error_mark_node;
}
- tree then_label_decl = build_label_decl("then", UNKNOWN_LOCATION);
- tree goto_then = build1(GOTO_EXPR, void_type_node, then_label_decl);
+ tree condition = this->current_expression;
- tree else_label_decl = build_label_decl("else", UNKNOWN_LOCATION);
- tree goto_else = build1(GOTO_EXPR, void_type_node, else_label_decl);
-
- auto cond_expr = build3(COND_EXPR, void_type_node, this->current_expression, goto_then, goto_else);
- append_statement(cond_expr);
-
- tree then_label_expr = build1(LABEL_EXPR, void_type_node, then_label_decl);
- append_statement(then_label_expr);
enter_scope();
-
visit_statements(branch.statements);
- tree mapping = leave_scope();
- append_statement(mapping);
- append_statement(goto_endif);
+ if (goto_append != NULL_TREE)
+ {
+ append_statement(goto_append);
+ }
+ tree then_body = leave_scope();
- tree else_label_expr = build1(LABEL_EXPR, void_type_node, else_label_decl);
- append_statement(else_label_expr);
+ return build3(COND_EXPR, void_type_node, condition, then_body, next);
}
void generic_visitor::visit(boot::import_declaration *)
@@ -1088,21 +1074,29 @@ namespace elna::gcc
void generic_visitor::visit(boot::while_statement *statement)
{
location_t prerequisite_location = get_location(&statement->branch().prerequisite().position());
- tree prerequisite_label_decl = build_label_decl("while_do", prerequisite_location);
- auto prerequisite_label_expr = build1_loc(prerequisite_location, LABEL_EXPR,
- void_type_node, prerequisite_label_decl);
- auto goto_check = build1(GOTO_EXPR, void_type_node, prerequisite_label_decl);
- tree branch_end_declaration = build_label_decl("while_end", UNKNOWN_LOCATION);
- tree branch_end_expression = build1_loc(UNKNOWN_LOCATION, LABEL_EXPR, void_type_node, branch_end_declaration);
+ tree while_check_label = build_label_decl("while_do", prerequisite_location);
+ tree while_end_label = build_label_decl("while_end", UNKNOWN_LOCATION);
+ tree goto_check = build1(GOTO_EXPR, void_type_node, while_check_label);
- append_statement(prerequisite_label_expr);
- make_if_branch(statement->branch(), goto_check);
+ tree result = NULL_TREE;
- for (const auto branch : statement->branches)
+ auto& branches = statement->branches;
+ for (auto it = branches.rbegin(); it != branches.rend(); ++it)
{
- make_if_branch(*branch, goto_check);
+ result = make_if_branch(**it, result, goto_check);
+ }
+ result = make_if_branch(statement->branch(), result, goto_check);
+
+ if (result != error_mark_node)
+ {
+ tree check_label_expr = build1_loc(prerequisite_location, LABEL_EXPR,
+ void_type_node, while_check_label);
+ tree end_label_expr = build1(LABEL_EXPR, void_type_node, while_end_label);
+
+ append_statement(check_label_expr);
+ append_statement(result);
+ append_statement(end_label_expr);
}
- append_statement(branch_end_expression);
this->current_expression = NULL_TREE;
}
diff --git a/gcc/gcc/elna-tree.cc b/gcc/gcc/elna-tree.cc
index ebe6a56..0227433 100644
--- a/gcc/gcc/elna-tree.cc
+++ b/gcc/gcc/elna-tree.cc
@@ -66,7 +66,7 @@ namespace elna::gcc
{
if (DECL_P(rvalue) && TREE_CODE(TREE_TYPE(rvalue)) == FUNCTION_TYPE)
{
- return build1(ADDR_EXPR, build_pointer_type_for_mode(TREE_TYPE(rvalue), VOIDmode, true), rvalue);
+ return build1(ADDR_EXPR, build_pointer_type(TREE_TYPE(rvalue)), rvalue);
}
else
{
@@ -241,11 +241,6 @@ namespace elna::gcc
return field_declaration;
}
- tree build_global_pointer_type(tree type)
- {
- return build_pointer_type_for_mode(type, VOIDmode, true);
- }
-
tree build_static_array_type(tree type, const std::uint64_t size)
{
tree upper_bound = build_int_cst_type(integer_type_node, size);
diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h
index 82ef5f1..0f8f6c7 100644
--- a/include/elna/boot/semantic.h
+++ b/include/elna/boot/semantic.h
@@ -177,6 +177,21 @@ namespace elna::boot
};
/**
+ * Type passed to a trait like #min or #max does not support
+ * the trait.
+ */
+ class unsupported_trait_type_error : public error
+ {
+ type actual;
+ std::string trait_name;
+
+ public:
+ unsupported_trait_type_error(const identifier& trait, type actual);
+
+ std::string what() const override;
+ };
+
+ /**
* Checks types.
*/
class type_analysis_visitor final : public walking_visitor, public error_container
diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h
index 23e1738..e0f20f3 100644
--- a/include/elna/gcc/elna-generic.h
+++ b/include/elna/gcc/elna-generic.h
@@ -40,7 +40,8 @@ namespace elna::gcc
void enter_scope();
tree leave_scope();
- void make_if_branch(boot::conditional_statements& branch, tree goto_endif);
+ tree make_if_branch(boot::conditional_statements& branch, tree next,
+ tree goto_append = NULL_TREE);
tree build_arithmetic_operation(boot::binary_expression *expression,
tree_code operator_code, tree left, tree right);
@@ -56,7 +57,6 @@ namespace elna::gcc
void build_assert_builtin(location_t call_location, const std::vector<boot::expression *>& arguments);
bool expect_trait_type_only(boot::traits_expression *trait);
- bool expect_trait_for_integral_type(boot::traits_expression *trait);
void visit_statements(const std::vector<boot::statement *>& statements);
bool assert_constant(location_t expression_location);
diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h
index f1402a7..556d52b 100644
--- a/include/elna/gcc/elna-tree.h
+++ b/include/elna/gcc/elna-tree.h
@@ -82,7 +82,6 @@ namespace elna::gcc
tree_code operator_code, tree left, tree right);
tree build_field(location_t location, tree record_type, const std::string name, tree type);
tree find_field_by_name(location_t expression_location, tree type, const std::string& field_name);
- tree build_global_pointer_type(tree type);
tree build_static_array_type(tree type, const std::uint64_t size);
tree build_enumeration_type(const std::vector<std::string>& members);
tree build_label_decl(const char *name, location_t loc);