aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--boot/type_check.cc69
-rw-r--r--gcc/gcc/elna-builtins.cc4
-rw-r--r--gcc/gcc/elna-generic.cc39
-rw-r--r--gcc/gcc/elna-tree.cc12
-rw-r--r--include/elna/boot/type_check.h8
-rw-r--r--include/elna/gcc/elna1.h5
-rw-r--r--testsuite/fail_compilation/while_condition.elna4
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.