diff options
| -rw-r--r-- | boot/type_check.cc | 69 | ||||
| -rw-r--r-- | gcc/gcc/elna-builtins.cc | 4 | ||||
| -rw-r--r-- | gcc/gcc/elna-generic.cc | 39 | ||||
| -rw-r--r-- | gcc/gcc/elna-tree.cc | 12 | ||||
| -rw-r--r-- | include/elna/boot/type_check.h | 8 | ||||
| -rw-r--r-- | include/elna/gcc/elna1.h | 5 | ||||
| -rw-r--r-- | testsuite/fail_compilation/while_condition.elna | 4 |
7 files changed, 104 insertions, 37 deletions
diff --git a/boot/type_check.cc b/boot/type_check.cc index 761c4b2..9bab537 100644 --- a/boot/type_check.cc +++ b/boot/type_check.cc @@ -107,6 +107,9 @@ namespace elna::boot case kind::for_loop: return "for-loop variable must be an array or a slice, got '" + this->actual.to_string() + "'"; + case kind::condition: + return "Condition must be a boolean, got '" + + this->actual.to_string() + "'"; default: __builtin_unreachable(); } @@ -212,6 +215,16 @@ namespace elna::boot return true; } + void type_analysis_visitor::visit_and_validate_condition(expression& condition) + { + condition.accept(this); + if (!is_primitive_type(condition.type_decoration, "Bool")) + { + add_error<type_kind_error>(condition.position(), + type_kind_error::kind::condition, condition.type_decoration); + } + } + /* * Checks whether derived has base in its record parent chain. * @@ -492,6 +505,61 @@ namespace elna::boot this->bag.leave(); } + void type_analysis_visitor::visit(repeat_statement *statement) + { + visit_and_validate_condition(statement->condition()); + + for (auto *body_statement : statement->body) + { + body_statement->accept(this); + } + } + + void type_analysis_visitor::visit(while_statement *statement) + { + visit_and_validate_condition(statement->branch().prerequisite()); + + for (auto *branch_statement : statement->branch().statements) + { + branch_statement->accept(this); + } + for (conditional_statements *branch : statement->branches) + { + visit_and_validate_condition(branch->prerequisite()); + + for (auto *branch_statement : branch->statements) + { + branch_statement->accept(this); + } + } + } + + void type_analysis_visitor::visit(if_statement *statement) + { + visit_and_validate_condition(statement->branch().prerequisite()); + + for (auto *branch_statement : statement->branch().statements) + { + branch_statement->accept(this); + } + for (conditional_statements *branch : statement->branches) + { + visit_and_validate_condition(branch->prerequisite()); + + for (auto *branch_statement : branch->statements) + { + branch_statement->accept(this); + } + } + if (statement->alternative != nullptr) + { + for (auto *branch_statement : *statement->alternative) + { + branch_statement->accept(this); + } + } + } + void type_analysis_visitor::visit(type_declaration *declaration) { std::vector<std::string> alias_path; @@ -564,6 +632,7 @@ namespace elna::boot type(std::make_shared<procedure_type>()), call->callable().type_decoration); } + // else callable is not declared which is already reported. } void type_analysis_visitor::visit(record_constructor_expression *expression) diff --git a/gcc/gcc/elna-builtins.cc b/gcc/gcc/elna-builtins.cc index 2790251..57d2875 100644 --- a/gcc/gcc/elna-builtins.cc +++ b/gcc/gcc/elna-builtins.cc @@ -27,7 +27,7 @@ namespace elna::gcc { void init_ttree() { - elna_int_type_node = long_integer_type_node; + elna_int_type_node = ptrdiff_type_node; elna_word_type_node = size_type_node; elna_char_type_node = unsigned_char_type_node; elna_pointer_type_node = ptr_type_node; @@ -37,7 +37,7 @@ namespace elna::gcc elna_bool_true_node = boolean_true_node; elna_bool_false_node = boolean_false_node; - elna_pointer_nil_node = null_pointer_node; + elna_word_one_node = build_int_cstu(elna_word_type_node, 1); } static diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc index ebf4f8f..c462924 100644 --- a/gcc/gcc/elna-generic.cc +++ b/gcc/gcc/elna-generic.cc @@ -138,8 +138,6 @@ namespace elna::gcc } else { - error_at(call_location, "'%s' cannot be called, it is not a procedure", - print_type(expression_type).c_str()); this->current_expression = error_mark_node; } } @@ -203,7 +201,7 @@ namespace elna::gcc { element->accept(this); CONSTRUCTOR_APPEND_ELT(tree_arguments, index, this->current_expression); - index = int_const_binop(PLUS_EXPR, index, size_one_node); + index = int_const_binop(PLUS_EXPR, index, elna_word_one_node); } this->current_expression = build_constructor(array_type, tree_arguments); } @@ -221,8 +219,7 @@ namespace elna::gcc expression->start().accept(this); tree start_index = fold_convert(elna_word_type_node, this->current_expression); - tree zero_based_offset = build2(MINUS_EXPR, elna_word_type_node, - start_index, size_one_node); + tree zero_based_offset = build2(MINUS_EXPR, elna_word_type_node, start_index, elna_word_one_node); tree slice_ptr; if (TREE_CODE(base_type) == ARRAY_TYPE) @@ -231,7 +228,7 @@ namespace elna::gcc // (1-based) start index since GCC handles the 1→0 conversion // via the domain lower bound. No -1 adjustment needed here. slice_ptr = build4_loc(location, ARRAY_REF, TREE_TYPE(base_type), - base, start_index, size_one_node, NULL_TREE); + base, start_index, elna_word_one_node, NULL_TREE); slice_ptr = build1(ADDR_EXPR, build_pointer_type(TREE_TYPE(base_type)), slice_ptr); } else @@ -246,7 +243,7 @@ namespace elna::gcc tree end_index = fold_convert(elna_word_type_node, this->current_expression); tree slice_length = build2(MINUS_EXPR, elna_word_type_node, end_index, start_index); - slice_length = build2(PLUS_EXPR, elna_word_type_node, slice_length, size_one_node); + slice_length = build2(PLUS_EXPR, elna_word_type_node, slice_length, elna_word_one_node); vec<constructor_elt, va_gc> *tree_arguments = nullptr; CONSTRUCTOR_APPEND_ELT(tree_arguments, ptr_field, slice_ptr); @@ -430,7 +427,7 @@ namespace elna::gcc } else if (std::holds_alternative<std::nullptr_t>(constant_value)) { - return elna_pointer_nil_node; + return null_pointer_node; } return NULL_TREE; } @@ -583,7 +580,7 @@ namespace elna::gcc { this->current_expression = do_pointer_arithmetic(expression->operation(), left, right, expression_location); - if (TREE_TYPE(this->current_expression) == ssizetype) + if (TREE_TYPE(this->current_expression) == ptrdiff_type_node) { this->current_expression = fold_convert(elna_int_type_node, this->current_expression); } @@ -753,7 +750,7 @@ namespace elna::gcc } else if (!declaration->is_extern && POINTER_TYPE_P(TREE_TYPE(declaration_tree))) { - DECL_INITIAL(declaration_tree) = elna_pointer_nil_node; + DECL_INITIAL(declaration_tree) = null_pointer_node; } { auto variable_symbol = this->bag.lookup(variable_identifier.name())->is_variable(); @@ -818,12 +815,12 @@ namespace elna::gcc tree element_type = TREE_TYPE(TREE_TYPE(designator)); this->current_expression = build4_loc(location, - ARRAY_REF, element_type, designator, offset, size_one_node, NULL_TREE); + ARRAY_REF, element_type, designator, offset, elna_word_one_node, NULL_TREE); } else if (expression->base().type_decoration.get<boot::slice_type>() != nullptr) { tree ptr_field = TYPE_FIELDS(TREE_TYPE(designator)); - offset = build2(MINUS_EXPR, elna_word_type_node, offset, size_one_node); + offset = build2(MINUS_EXPR, elna_word_type_node, offset, elna_word_one_node); tree slice_ptr = build3_loc(location, COMPONENT_REF, TREE_TYPE(ptr_field), designator, ptr_field, NULL_TREE); @@ -1060,15 +1057,6 @@ namespace elna::gcc tree goto_append) { branch.prerequisite().accept(this); - - if (TREE_TYPE(this->current_expression) != elna_bool_type_node) - { - error_at(get_location(&branch.prerequisite().position()), - "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 error_mark_node; - } tree condition = this->current_expression; enter_scope(); @@ -1143,7 +1131,7 @@ namespace elna::gcc { tree element_type = TREE_TYPE(TREE_TYPE(range_expression)); tree array_reference = build4_loc(location, ARRAY_REF, element_type, - range_expression, size_one_node, NULL_TREE, NULL_TREE); + range_expression, elna_word_one_node, NULL_TREE, NULL_TREE); start_pointer = build1(ADDR_EXPR, build_pointer_type(element_type), array_reference); length = TYPE_MAX_VALUE(TYPE_DOMAIN(TREE_TYPE(range_expression))); @@ -1170,13 +1158,12 @@ namespace elna::gcc tree control_variable_declaration = declare_local_variable( statement->control_variable, unqualified_info, start_pointer); - tree elna_one = build_int_cst_type(elna_word_type_node, 1); tree counter_declaration{ NULL_TREE }; if (statement->counter != nullptr) { auto counter_info = statement->symbols->lookup(statement->counter->name()); counter_declaration = declare_local_variable(*statement->counter, - *counter_info->is_variable(), elna_one); + *counter_info->is_variable(), elna_word_one_node); } auto [check_label, end_label] = build_loop_head(control_variable_declaration, end_pointer, LT_EXPR, location); @@ -1186,12 +1173,12 @@ namespace elna::gcc body_statement->accept(this); } tree pointer_plus = do_pointer_arithmetic(boot::binary_operator::sum, - control_variable_declaration, elna_one, location); + control_variable_declaration, elna_word_one_node, location); append_statement(build2(MODIFY_EXPR, void_type_node, control_variable_declaration, pointer_plus)); if (counter_declaration != NULL_TREE) { - tree counter_plus = fold_build2(PLUS_EXPR, elna_word_type_node, counter_declaration, elna_one); + tree counter_plus = fold_build2(PLUS_EXPR, elna_word_type_node, counter_declaration, elna_word_one_node); append_statement(build2(MODIFY_EXPR, void_type_node, counter_declaration, counter_plus)); } append_statement(build1(GOTO_EXPR, void_type_node, check_label)); diff --git a/gcc/gcc/elna-tree.cc b/gcc/gcc/elna-tree.cc index 7466f24..26936fe 100644 --- a/gcc/gcc/elna-tree.cc +++ b/gcc/gcc/elna-tree.cc @@ -140,7 +140,7 @@ namespace elna::gcc : fold_convert(TREE_TYPE(offset), size_in_bytes(TREE_TYPE(TREE_TYPE(pointer)))); offset = fold_build2(MULT_EXPR, TREE_TYPE(offset), offset, size_exp); - offset = fold_convert(sizetype, offset); + offset = fold_convert(size_type_node, offset); return fold_build2_loc(operation_location, POINTER_PLUS_EXPR, TREE_TYPE(pointer), pointer, offset); } @@ -153,14 +153,14 @@ namespace elna::gcc tree size_exp = fold_convert(offset_type, size_in_bytes(TREE_TYPE(pointer_type))); tree convert_expression = fold_build2(MULT_EXPR, offset_type, right, size_exp); - convert_expression = fold_convert(sizetype, convert_expression); + convert_expression = fold_convert(size_type_node, convert_expression); - convert_expression = fold_build1(NEGATE_EXPR, sizetype, convert_expression); + convert_expression = fold_build1(NEGATE_EXPR, size_type_node, convert_expression); return fold_build2_loc(operation_location, POINTER_PLUS_EXPR, pointer_type, left, convert_expression); } else if (POINTER_TYPE_P(left_type) && POINTER_TYPE_P(right_type) && left_type == right_type) { - return fold_build2_loc(operation_location, POINTER_DIFF_EXPR, ssizetype, left, right); + return fold_build2_loc(operation_location, POINTER_DIFF_EXPR, ptrdiff_type_node, left, right); } return error_mark_node; } @@ -202,8 +202,8 @@ namespace elna::gcc tree build_static_array_type(tree type, const std::uint64_t size) { - tree upper_bound = build_int_cst_type(integer_type_node, size); - tree range_type = build_range_type(integer_type_node, size_one_node, upper_bound); + tree upper_bound = build_int_cst_type(elna_word_type_node, size); + tree range_type = build_range_type(elna_word_type_node, elna_word_one_node, upper_bound); return build_array_type(type, range_type); } diff --git a/include/elna/boot/type_check.h b/include/elna/boot/type_check.h index e500007..f95c72b 100644 --- a/include/elna/boot/type_check.h +++ b/include/elna/boot/type_check.h @@ -96,7 +96,8 @@ namespace elna::boot enum class kind { record_base, - for_loop + for_loop, + condition }; type_kind_error(const source_position position, kind type_kind, const type& actual); @@ -227,6 +228,8 @@ namespace elna::boot static bool check_unresolved_symbol(const std::shared_ptr<alias_type>& alias, std::vector<std::string>& path); + void visit_and_validate_condition(expression& condition); + public: explicit type_analysis_visitor(symbol_bag bag, const target_info& target); @@ -239,6 +242,9 @@ namespace elna::boot void visit(procedure_call *call) override; void visit(case_statement *statement) override; void visit(for_statement *statement) override; + void visit(repeat_statement *statement) override; + void visit(while_statement *statement) override; + void visit(if_statement *statement) override; void visit(record_constructor_expression *expression) override; void visit(array_constructor_expression *expression) override; void visit(slicing_expression *expression) override; diff --git a/include/elna/gcc/elna1.h b/include/elna/gcc/elna1.h index 34cf091..580526a 100644 --- a/include/elna/gcc/elna1.h +++ b/include/elna/gcc/elna1.h @@ -27,7 +27,7 @@ enum elna_tree_index ELNA_TI_FLOAT_TYPE, ELNA_TI_BOOL_TRUE, ELNA_TI_BOOL_FALSE, - ELNA_TI_POINTER_NIL, + ELNA_TI_WORD_ONE, ELNA_TI_MAX }; @@ -43,7 +43,8 @@ extern std::vector<std::string> elna_include_dirs; #define elna_float_type_node elna_global_trees[ELNA_TI_FLOAT_TYPE] #define elna_bool_true_node elna_global_trees[ELNA_TI_BOOL_TRUE] #define elna_bool_false_node elna_global_trees[ELNA_TI_BOOL_FALSE] -#define elna_pointer_nil_node elna_global_trees[ELNA_TI_POINTER_NIL] +#define elna_word_one_node elna_global_trees[ELNA_TI_WORD_ONE] + /* Language-dependent contents of a type. */ struct GTY (()) lang_type { diff --git a/testsuite/fail_compilation/while_condition.elna b/testsuite/fail_compilation/while_condition.elna new file mode 100644 index 0000000..73fed95 --- /dev/null +++ b/testsuite/fail_compilation/while_condition.elna @@ -0,0 +1,4 @@ +begin + while 1 do (* @Error Condition must be a boolean, got 'Int' *) + end +end. |
