diff options
Diffstat (limited to 'boot/name_analysis.cc')
| -rw-r--r-- | boot/name_analysis.cc | 119 |
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()) |
