aboutsummaryrefslogtreecommitdiff
path: root/include
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 /include
parentbd2b80d6ac582b9f0bcd96c86d4b79bfdb64eca1 (diff)
downloadelna-eb1d068beeaaa420b558595751295eec35ad0c3c.tar.gz
Support variadic extern procedures
Diffstat (limited to 'include')
-rw-r--r--include/elna/boot/ast.h9
-rw-r--r--include/elna/boot/name_analysis.h77
-rw-r--r--include/elna/boot/result.h2
-rw-r--r--include/elna/boot/symbol.h3
-rw-r--r--include/elna/boot/type_check.h8
-rw-r--r--include/elna/gcc/elna-generic.h3
6 files changed, 90 insertions, 12 deletions
diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h
index 76fb94e..8f5d863 100644
--- a/include/elna/boot/ast.h
+++ b/include/elna/boot/ast.h
@@ -374,7 +374,7 @@ namespace elna::boot
const identifier& id() const;
bool exported() const;
/**
- * \return Attributes written in front of the identifier.
+ * \return Attributes attached to the identifier.
*/
std::vector<attribute> attributes;
@@ -501,7 +501,7 @@ namespace elna::boot
* absent.
*/
std::vector<type_expression *> base_arguments;
- /// Attributes written in front of the \c record keyword.
+ /// Attributes attached to the record itself.
std::vector<attribute> attributes;
record_type_expression(const source_position position,
@@ -642,6 +642,8 @@ namespace elna::boot
const return_t return_type;
const std::vector<field_declaration> parameters;
+ /// Attributes attached to the procedure type.
+ std::vector<attribute> attributes;
procedure_type_expression(const source_position position,
std::vector<field_declaration>&& parameters, return_t return_type = return_t());
@@ -911,6 +913,9 @@ namespace elna::boot
public:
std::vector<expression *> arguments;
+ /// Types the arguments after the parameters of a variadic procedure
+ /// are passed as, set by the type checker.
+ std::vector<type> variadic_types;
procedure_call(const source_position position, designator_expression *callable,
std::vector<expression *>&& arguments);
diff --git a/include/elna/boot/name_analysis.h b/include/elna/boot/name_analysis.h
index f2f2813..73f0a66 100644
--- a/include/elna/boot/name_analysis.h
+++ b/include/elna/boot/name_analysis.h
@@ -67,6 +67,15 @@ namespace elna::boot
};
/**
+ * Attributes the compiler knows.
+ */
+ enum class attribute_kind
+ {
+ aligned,
+ varargs
+ };
+
+ /**
* Error applying an attribute.
*/
class attribute_error final : public diagnostic
@@ -79,7 +88,9 @@ namespace elna::boot
unsupported,
argument_count,
not_constant,
- invalid_alignment
+ invalid_alignment,
+ unexpected_arguments,
+ missing_parameter
};
attribute_error(const source_position position, const std::string& name, kind attribute_kind);
@@ -202,16 +213,66 @@ namespace elna::boot
procedure_type::return_t build_return_type(
const procedure_type_expression::return_t& return_type);
std::pair<procedure_type, std::vector<std::string>> build_procedure(
- procedure_type_expression& expression);
+ procedure_type_expression& expression, bool variadic_supported);
ordered_map<field_info> build_composite_type(const std::vector<field_declaration>& fields,
- ordered_map<field_origin>& field_names, const type& aggregate,
- bool supported = true);
+ ordered_map<field_origin>& field_names, const type& aggregate);
/*
- * Reads the alignment out of the attributes written in front of a
- * declaration, reporting the ones that do not belong there.
+ * What the attributes attached to a declaration decide.
*/
- std::optional<std::size_t> evaluate_alignment(const std::vector<attribute>& attributes,
- bool supported);
+ struct attribute_values
+ {
+ std::optional<std::size_t> alignment;
+ bool variadic{ false };
+ };
+ static std::optional<attribute_kind> parse_attribute(const std::string& name);
+ /*
+ * Reads the attributes attached to a declaration, reporting the ones
+ * that do not belong there. The declaration accepts the attributes
+ * passed as template arguments.
+ */
+ template<attribute_kind... supported>
+ attribute_values evaluate_attributes(const std::vector<attribute>& attributes)
+ {
+ constexpr auto is_supported = [](const attribute_kind checked)
+ {
+ return ((checked == supported) || ...);
+ };
+ attribute_values result;
+
+ for (const attribute& written : attributes)
+ {
+ const std::string& name = written.name().name();
+ const source_position position = written.name().position();
+ const std::optional<attribute_kind> written_kind = parse_attribute(name);
+
+ if (!written_kind.has_value())
+ {
+ add_error<attribute_error>(position, name, attribute_error::kind::unknown);
+ }
+ else if (!is_supported(written_kind.value()))
+ {
+ add_error<attribute_error>(position, name, attribute_error::kind::unsupported);
+ }
+ else if (written_kind.value() == attribute_kind::aligned)
+ {
+ evaluate_alignment(written, result.alignment);
+ }
+ else if (!written.arguments().empty())
+ {
+ add_error<attribute_error>(position, name, attribute_error::kind::unexpected_arguments);
+ }
+ else if (result.variadic)
+ {
+ add_error<attribute_error>(position, name, attribute_error::kind::duplicate);
+ }
+ else
+ {
+ result.variadic = true;
+ }
+ }
+ return result;
+ }
+ void evaluate_alignment(const attribute& written, std::optional<std::size_t>& alignment);
/*
* Resolves a type expression, reporting names that denote something
* other than a type.
diff --git a/include/elna/boot/result.h b/include/elna/boot/result.h
index 6defcb8..a8ad73b 100644
--- a/include/elna/boot/result.h
+++ b/include/elna/boot/result.h
@@ -862,6 +862,8 @@ namespace elna::boot
type_properties single_properties;
type_properties double_properties;
type_properties bool_properties;
+ /// C's \c int, the type narrower variadic arguments are promoted to.
+ type_properties c_int_properties;
};
template<template<typename, typename> typename C, template<typename> typename Alloc = std::allocator>
diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h
index e9c9a0c..1ca5deb 100644
--- a/include/elna/boot/symbol.h
+++ b/include/elna/boot/symbol.h
@@ -201,6 +201,9 @@ namespace elna::boot
std::vector<type> parameters;
const return_t return_type;
+ /// Whether further arguments may follow the parameters, as with a C
+ /// variadic function.
+ bool variadic{ false };
explicit procedure_type(return_t return_type = return_t());
};
diff --git a/include/elna/boot/type_check.h b/include/elna/boot/type_check.h
index e948ada..5faec43 100644
--- a/include/elna/boot/type_check.h
+++ b/include/elna/boot/type_check.h
@@ -97,7 +97,8 @@ namespace elna::boot
dereference_of_parameter,
parameter_arithmetic,
zero_sized,
- not_addressable
+ not_addressable,
+ variadic_argument
};
type_requirement_error(const source_position position,
@@ -271,6 +272,11 @@ namespace elna::boot
const procedure_info& procedure);
void check_return(const procedure_body& body, const source_position position,
const std::string& name);
+ /*
+ * Checks an argument passed after the parameters of a variadic procedure
+ * and returns the type it is passed as.
+ */
+ type promote_variadic_argument(const expression& argument);
protected:
void visit_entry_point(unit *unit) override;
diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h
index c0c23b1..eec6cb4 100644
--- a/include/elna/gcc/elna-generic.h
+++ b/include/elna/gcc/elna-generic.h
@@ -57,7 +57,8 @@ namespace elna::gcc
void build_case_integral(boot::case_statement *statement, tree condition_expression);
void build_case_general(boot::case_statement *statement, tree condition_expression);
void build_procedure_call(location_t call_location,
- tree procedure_address, const std::vector<boot::expression *>& arguments);
+ tree procedure_address, const std::vector<boot::expression *>& arguments,
+ const std::vector<boot::type>& variadic_types);
bool build_builtin_procedures(boot::procedure_call *call);
void build_assert_builtin(location_t call_location, const std::vector<boot::expression *>& arguments);