aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-rw-r--r--boot/driver.cc2
-rw-r--r--boot/name_analysis.cc50
-rw-r--r--boot/symbol.cc15
-rw-r--r--boot/type_check.cc8
4 files changed, 68 insertions, 7 deletions
diff --git a/boot/driver.cc b/boot/driver.cc
index 14575f7..be52f23 100644
--- a/boot/driver.cc
+++ b/boot/driver.cc
@@ -66,6 +66,8 @@ namespace elna::boot
return '\'';
case '"':
return '"';
+ case '`':
+ return '`';
case '0':
return '\0';
default:
diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc
index 36faee1..9305cd2 100644
--- a/boot/name_analysis.cc
+++ b/boot/name_analysis.cc
@@ -144,6 +144,11 @@ namespace elna::boot
{
return "All constants should be initialized";
}
+ else if constexpr (std::is_same_v<T, array_dimension_type>)
+ {
+ return "Array dimension must be of type 'Word' or 'Int', but got '"
+ + payload.actual.to_string() + "'";
+ }
else if constexpr (std::is_same_v<T, kind>)
{
switch (payload)
@@ -162,6 +167,8 @@ namespace elna::boot
case enumeration_values:
return "Enumeration values should be omitted, given for the first member only,"
" or given for all members";
+ case array_dimension_size:
+ return "Array dimension must be greater than zero";
default:
__builtin_unreachable();
}
@@ -327,7 +334,7 @@ namespace elna::boot
resolving_visitor::resolving_visitor(symbol_bag& bag, const target_info& target,
const std::filesystem::path& module_path)
- : bag(bag), constant_evaluator(this->bag, target), module_file(module_path)
+ : bag(bag), target(target), constant_evaluator(this->bag, target), module_file(module_path)
{
}
@@ -580,15 +587,52 @@ namespace elna::boot
this->current_type = type();
return;
}
- const auto size_constant = this->constant_evaluator.evaluate_index(expression->dimensions());
- if (!size_constant.has_value())
+ if (!is_index_type(expression->dimensions().type_decoration, this->target))
+ {
+ add_error<declaration_format_error>(expression->dimensions().position(),
+ declaration_format_error::array_dimension_type{ expression->dimensions().type_decoration });
+ this->current_type = type();
+ return;
+ }
+
+ const std::optional<constant_value> evaluated =
+ this->constant_evaluator.evaluate(expression->dimensions());
+
+ if (!evaluated.has_value())
+ {
+ add_error<non_constant_expression_error>(expression->position(),
+ non_constant_expression_error::array_dimensions{ array_base });
+ this->current_type = type();
+ return;
+ }
+
+ const auto *literal = std::get_if<integer_literal>(&evaluated.value());
+
+ if (literal == nullptr)
{
add_error<non_constant_expression_error>(expression->position(),
non_constant_expression_error::array_dimensions{ array_base });
this->current_type = type();
return;
}
+ if (*literal <= 0)
+ {
+ add_error<declaration_format_error>(expression->dimensions().position(),
+ declaration_format_error::kind::array_dimension_size);
+ this->current_type = type();
+ return;
+ }
+
+ const std::optional<std::uint64_t> size_constant = literal->try_to<std::uint64_t>();
+
+ if (!size_constant.has_value())
+ {
+ add_error<declaration_format_error>(expression->dimensions().position(),
+ declaration_format_error::kind::array_dimension_size);
+ this->current_type = type();
+ return;
+ }
this->current_type = type(std::make_shared<array_type>(array_base, size_constant.value()));
}
diff --git a/boot/symbol.cc b/boot/symbol.cc
index 8feba4a..310ae8a 100644
--- a/boot/symbol.cc
+++ b/boot/symbol.cc
@@ -830,6 +830,21 @@ namespace elna::boot
|| is_float_type(checked);
}
+ bool is_index_type(const type& checked, const target_info& target)
+ {
+ const type unaliased = resolve_underlying_type(checked);
+ if (const auto primitive = unaliased.get<primitive_type>())
+ {
+ const bool is_int = primitive->identifier.starts_with("Int")
+ && primitive->properties.size == target.int_properties.front().size;
+ const bool is_word = primitive->identifier.starts_with("Word")
+ && primitive->properties.size == target.word_properties.front().size;
+
+ return is_int || is_word;
+ }
+ return false;
+ }
+
bool is_integral_type(const type& checked)
{
return is_integer_type(checked) || is_word_type(checked);
diff --git a/boot/type_check.cc b/boot/type_check.cc
index 797282c..5a8170a 100644
--- a/boot/type_check.cc
+++ b/boot/type_check.cc
@@ -250,7 +250,7 @@ namespace elna::boot
return "Condition must be a boolean expression, but got '"
+ this->actual.to_string() + "'";
case array_index:
- return "Array index must be an integral type, but got '"
+ return "Array index must be of type 'Word' or 'Int', but got '"
+ this->actual.to_string() + "'";
case non_indexable:
return "Indexing is not allowed on type '"
@@ -1528,12 +1528,12 @@ namespace elna::boot
{
walking_visitor::visit(expression);
- if (!is_integral_type(resolve_underlying_type(expression->start().type_decoration)))
+ if (!is_index_type(expression->start().type_decoration, this->target))
{
add_error<type_requirement_error>(expression->start().position(),
expression->start().type_decoration, type_requirement_error::kind::array_index);
}
- if (!is_integral_type(resolve_underlying_type(expression->end().type_decoration)))
+ if (!is_index_type(expression->end().type_decoration, this->target))
{
add_error<type_requirement_error>(expression->end().position(),
expression->end().type_decoration, type_requirement_error::kind::array_index);
@@ -1551,7 +1551,7 @@ namespace elna::boot
add_error<type_requirement_error>(expression->position(),
expression->base().type_decoration, type_requirement_error::kind::non_indexable);
}
- if (!is_integral_type(resolve_underlying_type(expression->index().type_decoration)))
+ if (!is_index_type(expression->index().type_decoration, this->target))
{
add_error<type_requirement_error>(expression->index().position(),
expression->index().type_decoration, type_requirement_error::kind::array_index);