diff options
Diffstat (limited to 'boot/name_analysis.cc')
| -rw-r--r-- | boot/name_analysis.cc | 112 |
1 files changed, 62 insertions, 50 deletions
diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc index caff18b..4a1a0ca 100644 --- a/boot/name_analysis.cc +++ b/boot/name_analysis.cc @@ -69,17 +69,21 @@ namespace elna::boot { using enum kind; case unknown: - return "Attribute '#" + this->name + "' not declared"; + return "Attribute '" + this->name + "' not declared"; case duplicate: - return "Attribute '#" + this->name + "' specified more than once"; + return "Attribute '" + this->name + "' specified more than once"; case unsupported: - return "Attribute '#" + this->name + "' is not supported in this position"; + return "Attribute '" + this->name + "' is not supported in this position"; case argument_count: - return "Attribute '#" + this->name + "' takes exactly one argument"; + return "Attribute '" + this->name + "' takes exactly one argument"; case not_constant: - return "Attribute '#" + this->name + "' requires a constant expression"; + return "Attribute '" + this->name + "' requires a constant expression"; case invalid_alignment: return "Alignment must be a power of two"; + case unexpected_arguments: + return "Attribute '" + this->name + "' takes no arguments"; + case missing_parameter: + return "Attribute '" + this->name + "' requires at least one parameter"; default: __builtin_unreachable(); } @@ -320,7 +324,7 @@ namespace elna::boot } std::pair<procedure_type, std::vector<std::string>> resolving_visitor::build_procedure( - procedure_type_expression& expression) + procedure_type_expression& expression, const bool variadic_supported) { const procedure_type::return_t result_return = build_return_type(expression.return_type); std::pair<procedure_type, std::vector<std::string>> result_type{ @@ -332,65 +336,70 @@ namespace elna::boot for (const auto& parameter_name : parameter_names) { - evaluate_alignment(parameter_name.attributes, false); + evaluate_attributes<>(parameter_name.attributes); result_type.first.parameters.push_back(parameter_type); result_type.second.push_back(parameter_name.name()); } } + result_type.first.variadic = variadic_supported + ? evaluate_attributes<attribute_kind::varargs>(expression.attributes).variadic + : evaluate_attributes<>(expression.attributes).variadic; + + if (result_type.first.variadic && result_type.first.parameters.empty()) + { + add_error<attribute_error>(expression.position(), "varargs", + attribute_error::kind::missing_parameter); + } return result_type; } - std::optional<std::size_t> resolving_visitor::evaluate_alignment( - const std::vector<attribute>& attributes, const bool supported) + std::optional<attribute_kind> resolving_visitor::parse_attribute(const std::string& name) { - std::optional<std::size_t> result; + if (name == "aligned") + { + return attribute_kind::aligned; + } + if (name == "varargs") + { + return attribute_kind::varargs; + } + return std::nullopt; + } - for (const attribute& written : attributes) + void resolving_visitor::evaluate_alignment(const attribute& written, std::optional<std::size_t>& alignment) + { + if (written.arguments().size() != 1) { - if (written.name().name() != "aligned") - { - add_error<attribute_error>(written.name().position(), written.name().name(), - attribute_error::kind::unknown); - } - else if (!supported) - { - add_error<attribute_error>(written.name().position(), written.name().name(), - attribute_error::kind::unsupported); - } - else if (written.arguments().size() != 1) - { - add_error<attribute_error>(written.name().position(), written.name().name(), - attribute_error::kind::argument_count); - } - else if (result.has_value()) - { - add_error<attribute_error>(written.name().position(), written.name().name(), - attribute_error::kind::duplicate); - } - else if (auto value = this->constant_evaluator.evaluate_index(*written.arguments().front())) + add_error<attribute_error>(written.name().position(), written.name().name(), + attribute_error::kind::argument_count); + } + else if (alignment.has_value()) + { + add_error<attribute_error>(written.name().position(), written.name().name(), + attribute_error::kind::duplicate); + } + else if (auto value = this->constant_evaluator.evaluate_index(*written.arguments().front())) + { + if (value.value() == 0 || (value.value() & (value.value() - 1)) != 0) { - if (value.value() == 0 || (value.value() & (value.value() - 1)) != 0) - { - add_error<attribute_error>(written.arguments().front()->position(), - written.name().name(), attribute_error::kind::invalid_alignment); - } - else - { - result = value; - } + add_error<attribute_error>(written.arguments().front()->position(), + written.name().name(), attribute_error::kind::invalid_alignment); } else { - add_error<attribute_error>(written.arguments().front()->position(), - written.name().name(), attribute_error::kind::not_constant); + alignment = value; } } - return result; + else + { + add_error<attribute_error>(written.arguments().front()->position(), + written.name().name(), attribute_error::kind::not_constant); + } } ordered_map<field_info> resolving_visitor::build_composite_type( const std::vector<field_declaration>& fields, - ordered_map<field_origin>& field_names, const type& aggregate, const bool supported) + ordered_map<field_origin>& field_names, const type& aggregate) { ordered_map<field_info> result; @@ -401,7 +410,7 @@ namespace elna::boot for (const identifier_definition& field_name : field.first) { const std::optional<std::size_t> alignment = - evaluate_alignment(field_name.attributes, supported); + evaluate_attributes<attribute_kind::aligned>(field_name.attributes).alignment; auto [existing, inserted] = field_names.insert(field_name.name(), field_origin{ .position = field.second->position(), .base_type = type() }); @@ -522,7 +531,8 @@ namespace elna::boot auto variable_symbol = register_variable(variable_identifier.name(), variable_type, declaration->position(), declaration->is_extern); variable_symbol->exported = variable_identifier.exported(); - variable_symbol->alignment = evaluate_alignment(variable_identifier.attributes, true); + variable_symbol->alignment = + evaluate_attributes<attribute_kind::aligned>(variable_identifier.attributes).alignment; variable_symbol->value = computed; } } @@ -690,7 +700,8 @@ namespace elna::boot ordered_map<field_origin> field_names; collect_field_names(result_type->base, field_names); result_type->fields = build_composite_type(expression->fields, field_names, type(result_type)); - result_type->alignment = evaluate_alignment(expression->attributes, true); + result_type->alignment = + evaluate_attributes<attribute_kind::aligned>(expression->attributes).alignment; this->current_type = type(result_type); } @@ -698,7 +709,7 @@ namespace elna::boot void resolving_visitor::visit(procedure_type_expression *expression) { std::shared_ptr<procedure_type> const result_type = - std::make_shared<procedure_type>(std::move(build_procedure(*expression).first)); + std::make_shared<procedure_type>(std::move(build_procedure(*expression, true).first)); this->current_type = type(result_type); } @@ -1418,7 +1429,8 @@ namespace elna::boot // is why the body sees them too. const std::shared_ptr<symbol_table> scope = this->bag.enter(); const std::vector<type> type_parameters = enter_parameters(declaration->parameters); - auto [heading, parameter_names] = build_procedure(declaration->heading()); + auto [heading, parameter_names] = + build_procedure(declaration->heading(), !declaration->body.has_value()); std::shared_ptr<procedure_info> info; if (declaration->body.has_value()) |
