aboutsummaryrefslogtreecommitdiff
path: root/boot/name_analysis.cc
diff options
context:
space:
mode:
Diffstat (limited to 'boot/name_analysis.cc')
-rw-r--r--boot/name_analysis.cc112
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())