diff options
Diffstat (limited to 'boot')
| -rw-r--r-- | boot/evaluator.cc | 35 | ||||
| -rw-r--r-- | boot/lexer.ll | 8 | ||||
| -rw-r--r-- | boot/parser.yy | 4 | ||||
| -rw-r--r-- | boot/result.cc | 57 | ||||
| -rw-r--r-- | boot/type_check.cc | 34 |
5 files changed, 101 insertions, 37 deletions
diff --git a/boot/evaluator.cc b/boot/evaluator.cc index 14b8ea3..56ba270 100644 --- a/boot/evaluator.cc +++ b/boot/evaluator.cc @@ -21,7 +21,6 @@ along with GCC; see the file COPYING3. If not see #include <algorithm> #include <cstddef> -#include <cstdint> #include <limits> #include <ranges> @@ -212,27 +211,23 @@ namespace elna::boot { type const decoration = subject.type_decoration; - if (is_primitive_type(decoration, "Int")) + if (is_primitive_type(decoration, "Int") || is_primitive_type(decoration, "Word")) { return constant_value{ static_cast<literal<integer_literal>&>(subject).value }; } - if (is_primitive_type(decoration, "Word")) - { - return constant_value{ static_cast<literal<integer_literal>&>(subject).value }; - } - if (is_primitive_type(decoration, "Float")) + else if (is_primitive_type(decoration, "Float")) { return constant_value{ static_cast<literal<double>&>(subject).value }; } - if (is_primitive_type(decoration, "Bool")) + else if (is_primitive_type(decoration, "Bool")) { return constant_value{ static_cast<literal<bool>&>(subject).value }; } - if (is_primitive_type(decoration, "Char")) + else if (is_primitive_type(decoration, "Char")) { return constant_value{ static_cast<literal<unsigned char>&>(subject).value }; } - if (is_primitive_type(decoration, "Pointer")) + else if (is_primitive_type(decoration, "Pointer")) { return constant_value{ std::nullptr_t{} }; } @@ -289,7 +284,7 @@ namespace elna::boot { auto enumeration_position = std::distance(enumeration->members.begin(), member_iterator) + 1; return constant_value{ - integer_literal::from(static_cast<std::int32_t>(enumeration_position)) + integer_literal::from(static_cast<std::size_t>(enumeration_position)) }; } return std::nullopt; @@ -704,14 +699,14 @@ namespace elna::boot { if (auto size = evaluate_traits_size(subject.types.front())) { - return constant_value{ integer_literal::from(static_cast<std::uint32_t>(size.value())) }; + return constant_value{ integer_literal::from(size.value()) }; } } else if (subject.name.name() == "alignment") { if (auto alignment = evaluate_traits_alignment(subject.types.front())) { - return constant_value{ integer_literal::from(static_cast<std::uint32_t>(alignment.value())) }; + return constant_value{ integer_literal::from(alignment.value()) }; } } else if (subject.name.name() == "min") @@ -720,11 +715,11 @@ namespace elna::boot if (is_primitive_type(resolved, "Int")) { - return constant_value{ integer_literal::from(std::numeric_limits<std::int32_t>::min()) }; + return constant_value{ integer_literal::from(std::numeric_limits<std::ptrdiff_t>::min()) }; } if (is_primitive_type(resolved, "Word")) { - return constant_value{ integer_literal::from<std::uint32_t>(0) }; + return constant_value{ integer_literal::from<std::size_t>(0) }; } if (is_primitive_type(resolved, "Char")) { @@ -740,7 +735,7 @@ namespace elna::boot } if (auto enumeration = resolved.get<enumeration_type>()) { - return constant_value{ integer_literal::from<std::int32_t>(1) }; + return constant_value{ integer_literal::from<std::size_t>(1) }; } } else if (subject.name.name() == "max") @@ -749,11 +744,11 @@ namespace elna::boot if (is_primitive_type(resolved, "Int")) { - return constant_value{ integer_literal::from(std::numeric_limits<std::int32_t>::max()) }; + return constant_value{ integer_literal::from(std::numeric_limits<std::ptrdiff_t>::max()) }; } if (is_primitive_type(resolved, "Word")) { - return constant_value{ integer_literal::from(std::numeric_limits<std::uint32_t>::max()) }; + return constant_value{ integer_literal::from(std::numeric_limits<std::size_t>::max()) }; } if (is_primitive_type(resolved, "Char")) { @@ -769,7 +764,7 @@ namespace elna::boot } if (auto enumeration = resolved.get<enumeration_type>()) { - return constant_value{ integer_literal::from(static_cast<std::int32_t>(enumeration->members.size())) }; + return constant_value{ integer_literal::from(enumeration->members.size()) }; } } else if (subject.name.name() == "offset") @@ -786,7 +781,7 @@ namespace elna::boot if (field_search != std::cend(record_layout.value().offset_map)) { - return constant_value{ integer_literal::from(static_cast<std::uint32_t>(field_search->second)) }; + return constant_value{ integer_literal::from(field_search->second) }; } } } diff --git a/boot/lexer.ll b/boot/lexer.ll index 89fe85c..ba54433 100644 --- a/boot/lexer.ll +++ b/boot/lexer.ll @@ -174,7 +174,7 @@ to { return yy::parser::make_TRAIT(yytext + 1, this->location); } [[:digit:]]+u { - unsigned long result = strtoul(yytext, NULL, 10); + std::uint64_t result = strtoull(yytext, NULL, 10); if (errno == ERANGE) { @@ -186,7 +186,7 @@ to { } } [[:digit:]]+ { - long result = strtol(yytext, NULL, 10); + std::int64_t result = strtoll(yytext, NULL, 10); if (errno == ERANGE) { @@ -198,7 +198,7 @@ to { } } 0[x|X]{HIGIT}+ { - unsigned long result = strtoul(yytext, NULL, 16); + std::uint64_t result = strtoull(yytext, NULL, 16); if (errno == ERANGE) { @@ -210,7 +210,7 @@ to { } } 0[b|B]{BIGIT}+ { - unsigned long result = strtoul(yytext, NULL, 2); + std::uint64_t result = strtoull(yytext, NULL, 2); if (errno == ERANGE) { diff --git a/boot/parser.yy b/boot/parser.yy index 670a265..bc0cb53 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -78,8 +78,8 @@ along with GCC; see the file COPYING3. If not see %token <std::string> IDENTIFIER %token <std::string> TRAIT -%token <std::int32_t> INTEGER -%token <std::uint32_t> WORD +%token <std::int64_t> INTEGER +%token <std::uint64_t> WORD %token <double> FLOAT %token <std::string> CHARACTER %token <std::string> STRING diff --git a/boot/result.cc b/boot/result.cc index 4d4c20f..f769625 100644 --- a/boot/result.cc +++ b/boot/result.cc @@ -17,6 +17,7 @@ along with GCC; see the file COPYING3. If not see #include "elna/boot/result.h" +#include <cstring> #include <numeric> namespace elna::boot @@ -340,6 +341,16 @@ namespace elna::boot return written > 1 ? std::nullopt : std::make_optional(rop); } + bool integer_literal::fit_into(const std::size_t target_size) + { + if (fits_in(target_size * CHAR_BIT)) + { + this->m_size = target_size; + return true; + } + return false; + } + bool integer_literal::is_signed() const { return this->m_signed; @@ -350,6 +361,18 @@ namespace elna::boot return this->m_size; } + std::string integer_literal::to_string(const std::uint8_t base) const + { + // +1 sign, +1 null terminator + const size_t buffer_size = mpz_sizeinbase(this->raw, static_cast<int>(base)) + 2; + std::string result(buffer_size, '\0'); + + mpz_get_str(result.data(), base, this->raw); + result.resize(std::strlen(result.c_str())); + + return result; + } + void swap(integer_literal& lhs, integer_literal& rhs) noexcept { mpz_swap(lhs.raw, rhs.raw); @@ -357,22 +380,20 @@ namespace elna::boot std::swap(lhs.m_size, rhs.m_size); } - std::optional<integer_literal> integer_literal::check() && + bool integer_literal::fits_in(const std::size_t bits) const { std::size_t required_bits = mpz_sizeinbase(this->raw, 2); - if (!is_negative_minimum()) + if (!is_negative_minimum(bits)) { ++required_bits; // Add one bit for the sign. } - if (required_bits > bits() || (mpz_sgn(this->raw) < 0 && !is_signed())) - { - return std::nullopt; - } - else - { - return std::move(*this); - } + return required_bits <= bits && (mpz_sgn(this->raw) >= 0 || is_signed()); + } + + std::optional<integer_literal> integer_literal::check() && + { + return fits_in(bits()) ? std::make_optional(std::move(*this)) : std::nullopt; } bool integer_literal::is_negative_minimum(const std::size_t bits) const @@ -454,5 +475,19 @@ std::size_t std::hash<elna::boot::constant_aggregate<elna::boot::ordered_map>>:: std::size_t std::hash<elna::boot::integer_literal>::operator()(const elna::boot::integer_literal& key) const noexcept { - return std::hash<std::uint32_t>{}(key.to<std::uint32_t>()); + if (key.is_signed()) + { + if (auto converted = key.to_signed()) + { + return std::hash<std::ptrdiff_t>{}(*converted); + } + } + else + { + if (auto converted = key.to_unsigned()) + { + return std::hash<std::size_t>{}(*converted); + } + } + return 0; } diff --git a/boot/type_check.cc b/boot/type_check.cc index 07deb2d..529f66a 100644 --- a/boot/type_check.cc +++ b/boot/type_check.cc @@ -165,6 +165,11 @@ namespace elna::boot return "Type '" + this->actual.to_string() + "' cannot be converted to '" + payload.target.to_string() + "'"; } + else if constexpr (std::is_same_v<T, integer_literal_overflow>) + { + return "The number " + payload.overflow.to_string() + + " does not fit into the type '" + actual.to_string() + "'"; + } else if constexpr (std::is_same_v<T, kind>) { switch (payload) @@ -762,6 +767,17 @@ namespace elna::boot void type_analysis_visitor::visit(slicing_expression *expression) { walking_visitor::visit(expression); + + if (!is_integral_type(resolve_underlying_type(expression->start().type_decoration))) + { + add_error<type_mismatch_error>(expression->start().position(), + expression->start().type_decoration, type_mismatch_error::kind::array_index); + } + if (!is_integral_type(resolve_underlying_type(expression->end().type_decoration))) + { + add_error<type_mismatch_error>(expression->end().position(), + expression->end().type_decoration, type_mismatch_error::kind::array_index); + } } void type_analysis_visitor::visit(array_access_expression *expression) @@ -1008,4 +1024,22 @@ namespace elna::boot } } } + + void type_analysis_visitor::visit(literal<integer_literal> *expression) + { + bool narrowed{ false }; + if (expression->value.is_signed()) + { + narrowed = expression->value.fit_into(target.int_properties.size); + } + else + { + narrowed = expression->value.fit_into(target.word_properties.size); + } + if (!narrowed) + { + add_error<type_mismatch_error>(expression->position(), expression->type_decoration, + type_mismatch_error::integer_literal_overflow{ expression->value }); + } + } } |
