diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-07-15 23:19:58 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-07-15 23:50:57 +0200 |
| commit | d0a666507a6f11b65170c257fd483613f462f3f2 (patch) | |
| tree | 1a23edf414234defbb1b6a36aadcf3e7795e24dc | |
| parent | e7265af15f77abf60a899b3d53a59652b5ca71ea (diff) | |
| download | elna-d0a666507a6f11b65170c257fd483613f462f3f2.tar.gz | |
Use build3(COND_EXPR) for conditionals
| -rw-r--r-- | boot/semantic.cc | 31 | ||||
| -rw-r--r-- | gcc/gcc/elna-builtins.cc | 6 | ||||
| -rw-r--r-- | gcc/gcc/elna-generic.cc | 150 | ||||
| -rw-r--r-- | gcc/gcc/elna-tree.cc | 7 | ||||
| -rw-r--r-- | include/elna/boot/semantic.h | 15 | ||||
| -rw-r--r-- | include/elna/gcc/elna-generic.h | 4 | ||||
| -rw-r--r-- | include/elna/gcc/elna-tree.h | 1 |
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); |
