diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/elna/boot/ast.h | 9 | ||||
| -rw-r--r-- | include/elna/boot/name_analysis.h | 77 | ||||
| -rw-r--r-- | include/elna/boot/result.h | 2 | ||||
| -rw-r--r-- | include/elna/boot/symbol.h | 3 | ||||
| -rw-r--r-- | include/elna/boot/type_check.h | 8 | ||||
| -rw-r--r-- | include/elna/gcc/elna-generic.h | 3 |
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); |
