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.cc119
1 files changed, 94 insertions, 25 deletions
diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc
index a979a37..caff18b 100644
--- a/boot/name_analysis.cc
+++ b/boot/name_analysis.cc
@@ -50,8 +50,6 @@ namespace elna::boot
return "Symbol '" + this->name + "' not declared";
case not_a_type:
return "'" + this->name + "' is not a type";
- case local_export:
- return "Local symbol '" + this->name + "' cannot be exported";
default:
__builtin_unreachable();
}
@@ -59,6 +57,34 @@ namespace elna::boot
}, this->payload);
}
+ attribute_error::attribute_error(const source_position position, const std::string& name,
+ kind attribute_kind)
+ : diagnostic(position), name(name), m_kind(attribute_kind)
+ {
+ }
+
+ std::string attribute_error::what() const
+ {
+ switch (this->m_kind)
+ {
+ using enum kind;
+ case unknown:
+ return "Attribute '#" + this->name + "' not declared";
+ case duplicate:
+ return "Attribute '#" + this->name + "' specified more than once";
+ case unsupported:
+ return "Attribute '#" + this->name + "' is not supported in this position";
+ case argument_count:
+ return "Attribute '#" + this->name + "' takes exactly one argument";
+ case not_constant:
+ return "Attribute '#" + this->name + "' requires a constant expression";
+ case invalid_alignment:
+ return "Alignment must be a power of two";
+ default:
+ __builtin_unreachable();
+ }
+ }
+
std::optional<diagnostic_note> symbol_declaration_error::note() const
{
if (std::holds_alternative<redefinition>(this->payload))
@@ -306,6 +332,7 @@ namespace elna::boot
for (const auto& parameter_name : parameter_names)
{
+ evaluate_alignment(parameter_name.attributes, false);
result_type.first.parameters.push_back(parameter_type);
result_type.second.push_back(parameter_name.name());
}
@@ -313,19 +340,71 @@ namespace elna::boot
return result_type;
}
- ordered_map<type> resolving_visitor::build_composite_type(const std::vector<field_declaration>& fields,
- ordered_map<field_origin>& field_names, const type& aggregate)
+ std::optional<std::size_t> resolving_visitor::evaluate_alignment(
+ const std::vector<attribute>& attributes, const bool supported)
+ {
+ std::optional<std::size_t> result;
+
+ for (const attribute& written : attributes)
+ {
+ 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()))
+ {
+ 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;
+ }
+ }
+ else
+ {
+ add_error<attribute_error>(written.arguments().front()->position(),
+ written.name().name(), attribute_error::kind::not_constant);
+ }
+ }
+ return result;
+ }
+
+ 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<type> result;
+ ordered_map<field_info> result;
for (const auto& field : fields)
{
const type field_type = resolve_type(*field.second);
- for (const auto& field_name : field.first)
+ for (const identifier_definition& field_name : field.first)
{
+ const std::optional<std::size_t> alignment =
+ evaluate_alignment(field_name.attributes, supported);
auto [existing, inserted] = field_names.insert(field_name.name(),
field_origin{ .position = field.second->position(), .base_type = type() });
+
if (!inserted)
{
std::optional<std::string> base_name;
@@ -338,12 +417,12 @@ namespace elna::boot
base_name = alias->name;
}
}
- add_error<member_error>(field_name.position(), field_name.name(), aggregate,
+ add_error<member_error>(field_name.id().position(), field_name.name(), aggregate,
member_error::duplicate{ .original = existing->second.position, .base = base_name });
}
else
{
- result.insert(field_name.name(), field_type);
+ result.insert(field_name.name(), field_info(field_type, alignment));
}
}
}
@@ -432,16 +511,18 @@ namespace elna::boot
}
else if (!declaration->is_extern && resolve_aliases(variable_type).get<constant_type>() != nullptr)
{
- auto position_span = source_position(declaration->identifiers.front().id().position().start(),
+ auto position_span = source_position(
+ declaration->identifiers.front().id().position().start(),
declaration->identifiers.back().id().position().end());
add_error<declaration_format_error>(position_span,
declaration_format_error::not_initialized{ extract_identifiers(declaration->identifiers) });
}
- for (const identifier_definition& variable_identifier : declaration->identifiers)
+ for (const auto& variable_identifier : declaration->identifiers)
{
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->value = computed;
}
}
@@ -609,6 +690,7 @@ 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);
this->current_type = type(result_type);
}
@@ -1216,10 +1298,10 @@ namespace elna::boot
{
return false;
}
- for (const auto& [field_name, field_type] : link->fields)
+ for (const auto& [field_name, field] : link->fields)
{
alias_path.resize(saved_path);
- if (!find_alias_cycle(being_resolved, field_type, alias_path, in_record))
+ if (!find_alias_cycle(being_resolved, field.field_type, alias_path, in_record))
{
return false;
}
@@ -1407,19 +1489,6 @@ namespace elna::boot
__builtin_unreachable();
}
- void name_analysis_visitor::visit(variable_declaration *declaration)
- {
- resolving_visitor::visit(declaration);
- for (const identifier_definition& variable_identifier : declaration->identifiers)
- {
- if (variable_identifier.exported())
- {
- add_error<symbol_declaration_error>(variable_identifier.id().position(),
- variable_identifier.id().name(), symbol_declaration_error::kind::local_export);
- }
- }
- }
-
void name_analysis_visitor::visit(procedure_declaration *declaration)
{
if (declaration->body.has_value())