aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-08-21 00:05:03 +0200
committerEugen Wissner <belka@caraus.de>2026-08-21 00:05:03 +0200
commit39269cc68a32f6e1a7524b00da36a1fe4cc7fb8b (patch)
tree9558cd6107d60e22127faeddbdeac5031ee2fdbe /include
parent4f77ad5d019618893c59a0f8d5bfa6b98e50a3be (diff)
downloadelna-39269cc68a32f6e1a7524b00da36a1fe4cc7fb8b.tar.gz
Implement Single and Double floats
Diffstat (limited to 'include')
-rw-r--r--include/elna/boot/ast.h8
-rw-r--r--include/elna/boot/materialization.h12
-rw-r--r--include/elna/boot/name_analysis.h2
-rw-r--r--include/elna/boot/result.h207
-rw-r--r--include/elna/boot/symbol.h27
-rw-r--r--include/elna/gcc/elna-generic.h2
-rw-r--r--include/elna/gcc/elna-tree.h2
-rw-r--r--include/elna/gcc/elna1.h2
8 files changed, 198 insertions, 64 deletions
diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h
index a05233c..8425b54 100644
--- a/include/elna/boot/ast.h
+++ b/include/elna/boot/ast.h
@@ -79,7 +79,7 @@ namespace elna::boot
};
template<>
- struct literal_type_id<double>
+ struct literal_type_id<float_literal>
{
static constexpr int value = 2;
};
@@ -187,7 +187,7 @@ namespace elna::boot
virtual void visit(field_access_expression *) = 0;
virtual void visit(dereference_expression *) = 0;
virtual void visit(literal<integer_literal> *) = 0;
- virtual void visit(literal<double> *) = 0;
+ virtual void visit(literal<float_literal> *) = 0;
virtual void visit(literal<bool> *) = 0;
virtual void visit(literal<std::uint32_t> *) = 0;
virtual void visit(literal<std::nullptr_t> *) = 0;
@@ -236,7 +236,7 @@ namespace elna::boot
[[noreturn]] void visit(field_access_expression *) override;
[[noreturn]] void visit(dereference_expression *) override;
[[noreturn]] void visit(literal<integer_literal> *) override;
- [[noreturn]] void visit(literal<double> *) override;
+ [[noreturn]] void visit(literal<float_literal> *) override;
[[noreturn]] void visit(literal<bool> *) override;
[[noreturn]] void visit(literal<std::uint32_t> *) override;
[[noreturn]] void visit(literal<std::nullptr_t> *) override;
@@ -283,7 +283,7 @@ namespace elna::boot
void visit(field_access_expression *expression) override;
void visit(dereference_expression *expression) override;
void visit(literal<integer_literal> *) override;
- void visit(literal<double> *) override;
+ void visit(literal<float_literal> *) override;
void visit(literal<bool> *) override;
void visit(literal<std::uint32_t> *) override;
void visit(literal<std::nullptr_t> *) override;
diff --git a/include/elna/boot/materialization.h b/include/elna/boot/materialization.h
index 2c571c5..f3c720e 100644
--- a/include/elna/boot/materialization.h
+++ b/include/elna/boot/materialization.h
@@ -24,9 +24,18 @@ namespace elna::boot
class materialization_error final : public diagnostic
{
public:
- materialization_error(const source_position position);
+ enum class kind
+ {
+ integer_overflow,
+ real_overflow
+ };
+
+ materialization_error(const source_position position, kind error_kind);
std::string what() const override;
+
+ private:
+ kind m_kind;
};
class materialization_visitor final : public walking_visitor, public diagnostic_container
@@ -37,5 +46,6 @@ namespace elna::boot
explicit materialization_visitor(const target_info& target);
void visit(literal<integer_literal> *literal) override;
+ void visit(literal<float_literal> *literal) override;
};
}
diff --git a/include/elna/boot/name_analysis.h b/include/elna/boot/name_analysis.h
index 91b669c..50d9fe6 100644
--- a/include/elna/boot/name_analysis.h
+++ b/include/elna/boot/name_analysis.h
@@ -173,7 +173,7 @@ namespace elna::boot
void visit(for_statement *statement) override;
void visit(literal<integer_literal> *literal) override;
- void visit(literal<double> *literal) override;
+ void visit(literal<float_literal> *literal) override;
void visit(literal<bool> *literal) override;
void visit(literal<std::uint32_t> *literal) override;
void visit(literal<std::nullptr_t> *literal) override;
diff --git a/include/elna/boot/result.h b/include/elna/boot/result.h
index ccc95ca..b34c4d4 100644
--- a/include/elna/boot/result.h
+++ b/include/elna/boot/result.h
@@ -273,12 +273,24 @@ namespace elna::boot
/**
* Checks whether \p T is any of std::int*_t or std::uint*_t types.
*
- * Contrary to \c std::is_integral characters and booleans do not count.
+ * Contrary to \c std::is_integral_v characters and booleans do not count.
*
* \tparam T The examined type.
*/
template<typename T>
- inline constexpr bool is_integral = is_signed_v<T> || is_unsigned_v<T>;
+ inline constexpr bool is_integral_v = is_signed_v<T> || is_unsigned_v<T>;
+
+ /**
+ * Checks whether \p T is a \c float or \c double.
+ *
+ * Contrary to \c is_floating_point_v it considers only 32 and 64 bit
+ * floating point numbers.
+ *
+ * \tparam T The examined type.
+ */
+ template<typename T>
+ inline constexpr bool is_floating_point_v = std::is_same_v<T, float>
+ || std::is_same_v<T, double>;
struct integer_literal
{
@@ -337,69 +349,39 @@ namespace elna::boot
*/
std::optional<integer_literal> shr(const integer_literal& that) const;
- /**
- * \param that Operand.
- * \return Bitwise OR of \c this and \p that.
- */
integer_literal operator|(const integer_literal& that) const;
-
- /**
- * \param that Operand.
- * \return Bitwise AND of \c this and \p that.
- */
integer_literal operator&(const integer_literal& that) const;
-
- /**
- * \param that Operand.
- * \return Bitwise XOR of \c this and \p that.
- */
integer_literal operator^(const integer_literal& that) const;
-
- /**
- * \return Bitwise complement of \c this.
- */
integer_literal operator~() const;
- /**
- * \param that Comparand.
- * \return Whether \c this and \p that hold the same value.
- */
bool operator==(const integer_literal& that) const;
- /// \overload
- template<typename U>
- bool operator==(U that) const
- requires(is_unsigned_v<U> && sizeof(U) <= sizeof(unsigned long int))
+ template<typename T>
+ bool operator==(T that) const
+ requires(is_unsigned_v<T> && sizeof(T) <= sizeof(unsigned long int))
{
return mpz_cmp_ui(this->raw, that) == 0;
}
- /// \overload
- template<typename U>
- bool operator==(U that) const
- requires(is_signed_v<U> && sizeof(U) <= sizeof(signed long int))
+ template<typename T>
+ bool operator==(T that) const
+ requires(is_signed_v<T> && sizeof(T) <= sizeof(signed long int))
{
return mpz_cmp_si(this->raw, that) == 0;
}
- /**
- * \param that Comparand.
- * \return Ordering of \c this relative to \p that.
- */
std::weak_ordering operator<=>(const integer_literal& that) const;
- /// \overload
- template<typename U>
- std::weak_ordering operator<=>(U that) const
- requires(is_unsigned_v<U> && sizeof(U) <= sizeof(unsigned long int))
+ template<typename T>
+ std::weak_ordering operator<=>(T that) const
+ requires(is_unsigned_v<T> && sizeof(T) <= sizeof(unsigned long int))
{
return mpz_cmp_ui(this->raw, that) <=> 0;
}
- /// \overload
- template<typename U>
- std::weak_ordering operator<=>(U that) const
- requires(is_signed_v<U> && sizeof(U) <= sizeof(signed long int))
+ template<typename T>
+ std::weak_ordering operator<=>(T that) const
+ requires(is_signed_v<T> && sizeof(T) <= sizeof(signed long int))
{
return mpz_cmp_si(this->raw, that) <=> 0;
}
@@ -433,7 +415,7 @@ namespace elna::boot
*/
template<typename T>
std::optional<T> try_to() const
- requires is_integral<T>
+ requires is_integral_v<T>
{
if constexpr (is_signed_v<T>)
{
@@ -443,10 +425,6 @@ namespace elna::boot
{
return to_unsigned<T>();
}
- else
- {
- static_assert("integer_literal::to expected only integral types");
- }
}
/**
@@ -485,7 +463,7 @@ namespace elna::boot
*/
template<typename T>
static integer_literal from(T initial)
- requires is_integral<T>
+ requires is_integral_v<T>
{
integer_literal result{ std::is_signed_v<T>, sizeof(T) };
@@ -503,7 +481,7 @@ namespace elna::boot
*/
template<typename T>
static std::optional<integer_literal> from(std::size_t size, T initial)
- requires is_integral<T>
+ requires is_integral_v<T>
{
integer_literal result{ std::is_signed_v<T>, size };
@@ -567,6 +545,122 @@ namespace elna::boot
}
};
+ struct float_literal
+ {
+ enum class format_kind
+ {
+ binary32,
+ binary64
+ };
+
+ /**
+ * \tparam T Initializer type.
+ * \param initial Initial literal value.
+ * \return A literal constructed from the host value \p initial.
+ */
+ template<typename T>
+ static float_literal from(T initial)
+ requires is_floating_point_v<T>
+ {
+ if constexpr (std::is_same_v<T, float>)
+ {
+ return float_literal(format_kind::binary32, initial);
+ }
+ else if constexpr (std::is_same_v<T, double>)
+ {
+ return float_literal(format_kind::binary64, initial);
+ }
+ }
+
+ float_literal operator+(const float_literal& that) const;
+ float_literal operator-(const float_literal& that) const;
+ float_literal operator*(const float_literal& that) const;
+ float_literal operator/(const float_literal& that) const;
+ float_literal operator-() const;
+
+ bool operator==(const float_literal& that) const;
+
+ template<typename T>
+ bool operator==(T that) const
+ requires is_floating_point_v<T>
+ {
+ return this->raw == that;
+ }
+
+ std::partial_ordering operator<=>(const float_literal& that) const;
+
+ template<typename T>
+ bool operator<=>(T that) const
+ requires is_floating_point_v<T>
+ {
+ return this->raw <=> that;
+ }
+
+ /// \return Stored floating point number format.
+ format_kind format() const;
+
+ /**
+ * \return The stored value as a host \c double.
+ *
+ * Binary32 values are exactly representable as \c double, so this
+ * accessor is always lossless.
+ */
+ double value() const;
+
+ /**
+ * \return Whether the stored value is finite.
+ */
+ bool is_finite() const;
+
+ /**
+ * \return String representation.
+ */
+ std::string to_string() const;
+
+ /**
+ * Exports the stored value as a host \p T.
+ *
+ * This function tries to shrink or extend the value to fit into the
+ * target type if possible.
+ *
+ * \tparam Target type.
+ * \return The converted value, or \c std::nullopt if not enough precision.
+ */
+ template<typename T>
+ std::optional<T> try_to() const
+ requires is_floating_point_v<T>
+ {
+ if constexpr (std::is_same_v<T, float>)
+ {
+ float single = static_cast<float>(this->raw);
+
+ return static_cast<double>(single) == this->raw
+ ? std::optional(single)
+ : std::nullopt;
+ }
+ else if constexpr (std::is_same_v<T, double>)
+ {
+ return std::optional(static_cast<T>(this->raw));
+ }
+ }
+
+ /**
+ * Cast the value to the given size, reducing precision if needed.
+ *
+ * \param binary_format Result size.
+ * \return Cast result.
+ */
+ float_literal cast_to(format_kind binary_format) const;
+
+ private:
+ float_literal(format_kind binary_format, double value);
+
+ static float_literal rounded(format_kind binary_format, double value);
+
+ format_kind m_format;
+ double raw;
+ };
+
/**
* An associative container that contains key-value pairs with unique keys.
* Keys preserve the insertion order.
@@ -747,7 +841,8 @@ namespace elna::boot
std::array<type_properties, target_integer_count> word_properties;
type_properties pointer_properties;
type_properties char_properties;
- type_properties float_properties;
+ type_properties single_properties;
+ type_properties double_properties;
type_properties bool_properties;
};
@@ -762,7 +857,7 @@ namespace elna::boot
*/
using constant_value = std::variant<
integer_literal,
- double,
+ float_literal,
bool,
std::uint32_t,
std::nullptr_t,
@@ -907,3 +1002,9 @@ struct std::hash<elna::boot::integer_literal>
{
std::size_t operator()(const elna::boot::integer_literal& key) const noexcept;
};
+
+template<>
+struct std::hash<elna::boot::float_literal>
+{
+ std::size_t operator()(const elna::boot::float_literal& key) const noexcept;
+};
diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h
index 5817b38..1caba83 100644
--- a/include/elna/boot/symbol.h
+++ b/include/elna/boot/symbol.h
@@ -540,8 +540,33 @@ namespace elna::boot
bool is_primitive_type(const type& checked, const std::string& name);
/**
+ * Checks whether the given type is a fixed-size integer.
+ *
+ * \param checked The type to check.
+ * \return Whether the type is a fixed-size integer.
+ */
+ bool is_integer_type(const type& checked);
+
+ /**
+ * Checks whether the given type is a fixed-size word.
+ *
+ * \param checked The type to check.
+ * \return Whether the type is a fixed-size word.
+ */
+ bool is_word_type(const type& checked);
+
+ /**
+ * Checks whether the given type is a floating point primitive type
+ * (\c Single or \c Double).
+ *
+ * \param checked The type to check.
+ * \return Whether the type is a floating point primitive.
+ */
+ bool is_float_type(const type& checked);
+
+ /**
* Checks whether the given type is a numeric primitive type
- * (\c Int, \c Word, or \c Float).
+ * (\c Int, \c Word, \c Single, or \c Double).
*
* \param checked The type to check.
* \return Whether the type is a numeric primitive.
diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h
index 2d65a26..fd54ba5 100644
--- a/include/elna/gcc/elna-generic.h
+++ b/include/elna/gcc/elna-generic.h
@@ -74,7 +74,7 @@ namespace elna::gcc
void visit(boot::procedure_call *call) override;
void visit(boot::cast_expression *expression) override;
void visit(boot::literal<boot::integer_literal> *literal) override;
- void visit(boot::literal<double> *literal) override;
+ void visit(boot::literal<boot::float_literal> *literal) override;
void visit(boot::literal<bool> *boolean) override;
void visit(boot::literal<std::uint32_t> *character) override;
void visit(boot::literal<std::nullptr_t> *) override;
diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h
index 504b14c..f201e64 100644
--- a/include/elna/gcc/elna-tree.h
+++ b/include/elna/gcc/elna-tree.h
@@ -62,7 +62,7 @@ namespace elna::gcc
tree extract_constant(tree expression);
tree constant_to_tree(const boot::constant_value& value,
- const std::shared_ptr<symbol_table>& symbols, tree type = NULL_TREE);
+ const std::shared_ptr<symbol_table>& symbols, tree type);
template<typename... Args>
tree call_built_in(location_t call_location, const char *name, tree return_type, Args... arguments)
diff --git a/include/elna/gcc/elna1.h b/include/elna/gcc/elna1.h
index 96043f9..44a0c88 100644
--- a/include/elna/gcc/elna1.h
+++ b/include/elna/gcc/elna1.h
@@ -24,7 +24,6 @@ enum elna_tree_index
ELNA_TI_CHAR_TYPE,
ELNA_TI_BOOL_TYPE,
ELNA_TI_POINTER_TYPE,
- ELNA_TI_FLOAT_TYPE,
ELNA_TI_BOOL_TRUE,
ELNA_TI_BOOL_FALSE,
ELNA_TI_WORD_ONE,
@@ -41,7 +40,6 @@ extern std::vector<std::string> elna_include_dirs;
#define elna_char_type_node elna_global_trees[ELNA_TI_CHAR_TYPE]
#define elna_bool_type_node elna_global_trees[ELNA_TI_BOOL_TYPE]
#define elna_pointer_type_node elna_global_trees[ELNA_TI_POINTER_TYPE]
-#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_word_one_node elna_global_trees[ELNA_TI_WORD_ONE]