aboutsummaryrefslogtreecommitdiff
path: root/boot/type_check.cc
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-09-12 00:18:11 +0200
committerEugen Wissner <belka@caraus.de>2026-09-12 00:18:11 +0200
commiteb1d068beeaaa420b558595751295eec35ad0c3c (patch)
treea10aadd88ba358726573f7324ff6f9c489ebad77 /boot/type_check.cc
parentbd2b80d6ac582b9f0bcd96c86d4b79bfdb64eca1 (diff)
downloadelna-eb1d068beeaaa420b558595751295eec35ad0c3c.tar.gz
Support variadic extern procedures
Diffstat (limited to 'boot/type_check.cc')
-rw-r--r--boot/type_check.cc44
1 files changed, 43 insertions, 1 deletions
diff --git a/boot/type_check.cc b/boot/type_check.cc
index 8847693..5cdd2a2 100644
--- a/boot/type_check.cc
+++ b/boot/type_check.cc
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see
#include "elna/boot/evaluator.h"
#include "elna/boot/name_analysis.h"
+#include <climits>
#include <ranges>
#include <utility>
@@ -286,6 +287,9 @@ namespace elna::boot
case not_addressable:
return "Expression of type '" + this->actual.to_string()
+ "' is not addressable";
+ case variadic_argument:
+ return "Type '" + this->actual.to_string()
+ + "' cannot be passed as a variadic argument";
default:
__builtin_unreachable();
}
@@ -1337,6 +1341,34 @@ namespace elna::boot
procedure.parameters, bindings);
}
+ type type_analysis_visitor::promote_variadic_argument(const expression& argument)
+ {
+ const type resolved = resolve_underlying_type(argument.type_decoration);
+
+ if (resolved.get<array_type>() != nullptr || resolved.get<slice_type>() != nullptr)
+ {
+ add_error<type_requirement_error>(argument.position(), argument.type_decoration,
+ type_requirement_error::kind::variadic_argument);
+ return type();
+ }
+ if (is_primitive_type(resolved, "Single"))
+ {
+ return this->bag.lookup("Double")->is_type()->symbol;
+ }
+ if (is_discrete_type(resolved))
+ {
+ const std::optional<type_properties> properties = get_type_properties(resolved, this->target);
+
+ if (properties.has_value() && properties->size < this->target.c_int_properties.size)
+ {
+ const std::size_t bit_size = this->target.c_int_properties.size * CHAR_BIT;
+
+ return this->bag.lookup("Int" + std::to_string(bit_size))->is_type()->symbol;
+ }
+ }
+ return argument.type_decoration;
+ }
+
void type_analysis_visitor::visit(procedure_call *call)
{
const named_expression *reference = call->callable().is_named();
@@ -1388,7 +1420,17 @@ namespace elna::boot
++argument_iterator;
++type_iterator;
}
- if (call->arguments.size() != procedure->parameters.size())
+ while (procedure->variadic && argument_iterator != std::cend(call->arguments))
+ {
+ if (inferred == nullptr)
+ {
+ (*argument_iterator)->accept(this);
+ }
+ call->variadic_types.push_back(promote_variadic_argument(**argument_iterator));
+ ++argument_iterator;
+ }
+ if (call->arguments.size() < procedure->parameters.size()
+ || (!procedure->variadic && call->arguments.size() > procedure->parameters.size()))
{
if (auto *procedure_name = call->callable().is_named())
{