From 08d9c4292ebba3e320c1dbaca4fa06c83f6fc7fb Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sat, 29 Aug 2026 10:03:11 +0200 Subject: Fix procedure order resolution --- boot/name_analysis.cc | 823 +++++++++++++++++++++++++++++--------------------- 1 file changed, 475 insertions(+), 348 deletions(-) (limited to 'boot/name_analysis.cc') diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc index 10b8a8d..cf90e3d 100644 --- a/boot/name_analysis.cc +++ b/boot/name_analysis.cc @@ -202,13 +202,58 @@ namespace elna::boot } } - name_analysis_visitor::name_analysis_visitor(symbol_bag bag, const target_info& target, - std::filesystem::path module_file) - : bag(std::move(bag)), constant_evaluator(this->bag, target), module_file(std::move(module_file)) + /** + * Collects field names from a record type recursively, base first. + */ + static void collect_field_names(const type& composite_type, + ordered_map& names) { + auto record = resolve_underlying_type(composite_type).get(); + if (record == nullptr) + { + return; + } + if (!record->base.empty()) + { + collect_field_names(record->base, names); + } + for (auto& field : record->fields) + { + names.insert(field.first, field_origin{ .position = std::nullopt, .base_type = composite_type }); + } + } + + void forward_declaration_visitor::visit(unit *unit) + { + for (type_declaration *const type : unit->types) + { + type->accept(this); + } } - std::pair> name_analysis_visitor::build_procedure( + void forward_declaration_visitor::visit(type_declaration *declaration) + { + const std::string& type_identifier = declaration->identifier.name(); + + if (!this->unresolved.insert({ type_identifier, std::make_shared(type_identifier) }).second) + { + add_error(declaration->identifier.id().position(), + declaration->identifier.id().name(), + declaration_error::redefinition{ .original = declaration->position(), .file = {} }); + } + } + + resolving_visitor::resolving_visitor(symbol_bag& bag, const target_info& target, + const std::filesystem::path& module_path) + : bag(bag), constant_evaluator(this->bag, target), module_file(module_path) + { + } + + void resolving_visitor::visit(import_declaration *) + { + } + + std::pair> resolving_visitor::build_procedure( procedure_type_expression& expression) { procedure_type::return_t result_return; @@ -241,7 +286,70 @@ namespace elna::boot return result_type; } - std::optional name_analysis_visitor::lookup_pointer_like_field( + ordered_map resolving_visitor::build_composite_type(const std::vector& fields, + ordered_map& field_names, const type& aggregate) + { + ordered_map result; + + for (const auto& field : fields) + { + field.second->accept(this); + for (const auto& field_name : field.first) + { + auto [existing, inserted] = field_names.insert(field_name.name(), + field_origin{ .position = field.second->position(), .base_type = type() }); + if (!inserted) + { + std::optional base_name; + + if (!existing->second.position.has_value() + && !existing->second.base_type.empty()) + { + if (auto alias = existing->second.base_type.get()) + { + base_name = alias->name; + } + } + add_error(field_name.position(), field_name.name(), aggregate, + member_error::duplicate{ .original = existing->second.position, .base = base_name }); + } + else + { + result.insert(field_name.name(), this->current_type); + } + } + } + return result; + } + + type resolving_visitor::lookup_primitive_type(const std::string& name) + { + return this->bag.lookup(name)->is_type()->symbol; + } + + std::filesystem::path resolving_visitor::redefinition_file(const std::shared_ptr& original) const + { + return original->file != this->module_file ? original->file : std::filesystem::path{}; + } + + std::shared_ptr resolving_visitor::register_variable(const std::string& name, + const type& variable_type, const source_position position, const bool is_extern) + { + auto variable_symbol = std::make_shared(variable_type, is_extern); + variable_symbol->position.emplace(position); + variable_symbol->file = this->module_file; + + if (!this->bag.enter(name, variable_symbol)) + { + auto original = this->bag.lookup(name); + add_error(position, name, + declaration_error::redefinition{ .original = original->position, + .file = this->redefinition_file(original) }); + } + return variable_symbol; + } + + std::optional resolving_visitor::lookup_pointer_like_field( const std::string& field_name, const type& element_type) { if (field_name == "length") @@ -256,12 +364,7 @@ namespace elna::boot return std::nullopt; } - type name_analysis_visitor::lookup_primitive_type(const std::string& name) - { - return this->bag.lookup(name)->is_type()->symbol; - } - - type name_analysis_visitor::lookup_field(const type& composite_type, const std::string& field_name) + type resolving_visitor::lookup_field(const type& composite_type, const std::string& field_name) { const type resolved_type = resolve_underlying_type(composite_type); @@ -289,44 +392,40 @@ namespace elna::boot return type(); } - void name_analysis_visitor::visit(type_declaration *declaration) + void resolving_visitor::visit(variable_declaration *declaration) { - walking_visitor::visit(declaration); - auto resolved = this->bag.resolve(declaration->identifier.name(), this->current_type); - auto info = std::make_shared(type(resolved)); + declaration->variable_type().accept(this); + auto variable_type = this->current_type; + std::optional computed; - info->exported = declaration->identifier.exported(); - info->position.emplace(declaration->position()); - info->file = this->module_file; + if (declaration->initializer != nullptr) + { + declaration->initializer->accept(this); + computed = this->constant_evaluator.evaluate(*declaration->initializer); - if (!this->bag.enter(declaration->identifier.name(), info)) + if (this->bag.is_global() && !computed.has_value()) + { + add_error(declaration->initializer->position(), + non_constant_expression_error::initializer{ extract_identifiers(declaration->identifiers) }); + } + } + else if (resolve_aliases(variable_type).get() != nullptr) { - auto original = this->bag.lookup(declaration->identifier.name()); - add_error(declaration->identifier.id().position(), declaration->identifier.name(), - declaration_error::redefinition{ .original = original->position, - .file = this->redefinition_file(original) }); + auto position_span = source_position(declaration->identifiers.front().id().position().start(), + declaration->identifiers.back().id().position().end()); + add_error(position_span, + const_qualifier_error::not_initialized{ extract_identifiers(declaration->identifiers) }); } - } - - void name_analysis_visitor::visit(pointer_type_expression *expression) - { - walking_visitor::visit(expression); - this->current_type = type(std::make_shared(this->current_type)); - } - - void name_analysis_visitor::visit(constant_type_expression *expression) - { - walking_visitor::visit(expression); - - if (this->current_type.get() != nullptr) + for (const identifier_definition& variable_identifier : declaration->identifiers) { - add_error(expression->position(), - const_qualifier_error::kind::duplicate); + auto variable_symbol = register_variable(variable_identifier.name(), + variable_type, declaration->position(), declaration->is_extern); + variable_symbol->exported = variable_identifier.exported(); + variable_symbol->value = computed; } - this->current_type = type(std::make_shared(this->current_type)); } - void name_analysis_visitor::visit(array_type_expression *expression) + void resolving_visitor::visit(array_type_expression *expression) { expression->base().accept(this); auto array_base = this->current_type; @@ -347,70 +446,30 @@ namespace elna::boot this->current_type = type(std::make_shared(array_base, size_constant.value())); } - void name_analysis_visitor::visit(slice_type_expression *expression) + void resolving_visitor::visit(slice_type_expression *expression) { - walking_visitor::visit(expression); + expression->base().accept(this); this->current_type = type(std::make_shared(this->current_type)); } - /** - * Collects field names from a record type recursively, base first. - */ - static void collect_field_names(const type& composite_type, - ordered_map& names) + void resolving_visitor::visit(pointer_type_expression *expression) { - auto record = resolve_underlying_type(composite_type).get(); - if (record == nullptr) - { - return; - } - if (!record->base.empty()) - { - collect_field_names(record->base, names); - } - for (auto& field : record->fields) - { - names.insert(field.first, field_origin{ .position = std::nullopt, .base_type = composite_type }); - } + expression->base().accept(this); + this->current_type = type(std::make_shared(this->current_type)); } - ordered_map name_analysis_visitor::build_composite_type(const std::vector& fields, - ordered_map& field_names, const type& aggregate) + void resolving_visitor::visit(constant_type_expression *expression) { - ordered_map result; - - for (const auto& field : fields) + expression->base().accept(this); + if (this->current_type.get() != nullptr) { - field.second->accept(this); - for (const auto& field_name : field.first) - { - auto [existing, inserted] = field_names.insert(field_name.name(), - field_origin{ .position = field.second->position(), .base_type = type() }); - if (!inserted) - { - std::optional base_name; - - if (!existing->second.position.has_value() - && !existing->second.base_type.empty()) - { - if (auto alias = existing->second.base_type.get()) - { - base_name = alias->name; - } - } - add_error(field_name.position(), field_name.name(), aggregate, - member_error::duplicate{ .original = existing->second.position, .base = base_name }); - } - else - { - result.insert(field_name.name(), this->current_type); - } - } + add_error(expression->position(), + const_qualifier_error::kind::duplicate); } - return result; + this->current_type = type(std::make_shared(this->current_type)); } - void name_analysis_visitor::visit(record_type_expression *expression) + void resolving_visitor::visit(record_type_expression *expression) { std::shared_ptr result_type; if (expression->base.has_value()) @@ -451,66 +510,7 @@ namespace elna::boot this->current_type = type(result_type); } - void name_analysis_visitor::visit(record_constructor_expression *expression) - { - if (auto type_symbol = this->bag.lookup(expression->type_name.name())) - { - if (auto type_info = type_symbol->is_type()) - { - expression->type_decoration = type_info->symbol; - } - } - else - { - add_error(expression->type_name.position(), - expression->type_name.name(), declaration_error::kind::undeclared_type); - } - for (const field_initializer& initializer : expression->field_initializers) - { - initializer.value().accept(this); - if (!expression->type_decoration.empty() - && lookup_field(expression->type_decoration, initializer.name()).empty()) - { - add_error(initializer.id().position(), initializer.id().name(), - expression->type_decoration, member_error::kind::not_found); - } - } - this->current_type = type(); - } - - void name_analysis_visitor::visit(array_constructor_expression *expression) - { - for (auto *element : expression->elements) - { - element->accept(this); - } - const type element_type = expression->elements.front()->type_decoration; - expression->type_decoration = type(std::make_shared(element_type, - expression->elements.size())); - this->current_type = type(); - } - - void name_analysis_visitor::visit(slicing_expression *expression) - { - walking_visitor::visit(expression); - auto resolved_base = resolve_underlying_type(expression->base().type_decoration); - - if (auto pointer = resolved_base.get()) - { - expression->type_decoration = type(std::make_shared(pointer->base)); - } - else if (auto array = resolved_base.get()) - { - expression->type_decoration = type(std::make_shared(array->base)); - } - else if (auto slice = resolved_base.get()) - { - expression->type_decoration = type(slice); - } - this->current_type = type(); - } - - void name_analysis_visitor::visit(procedure_type_expression *expression) + void resolving_visitor::visit(procedure_type_expression *expression) { std::shared_ptr const result_type = std::make_shared(std::move(build_procedure(*expression).first)); @@ -518,12 +518,7 @@ namespace elna::boot this->current_type = type(result_type); } - void name_analysis_visitor::visit(extern_type_expression *) - { - this->current_type = type(std::make_shared()); - } - - void name_analysis_visitor::visit(enumeration_type_expression *expression) + void resolving_visitor::visit(enumeration_type_expression *expression) { std::vector member_names; member_names.reserve(expression->members.size()); @@ -552,114 +547,105 @@ namespace elna::boot this->current_type = type(result_type); } - std::filesystem::path name_analysis_visitor::redefinition_file( - const std::shared_ptr& original) const + void resolving_visitor::visit(extern_type_expression *) { - return original->file != this->module_file ? original->file : std::filesystem::path{}; + this->current_type = type(std::make_shared()); } - std::shared_ptr name_analysis_visitor::register_variable(const std::string& name, - const bool is_extern, const source_position position) + void resolving_visitor::visit(assign_statement *statement) { - auto variable_symbol = std::make_shared(this->current_type, is_extern); - variable_symbol->position.emplace(position); - variable_symbol->file = this->module_file; + statement->lvalue().accept(this); + statement->rvalue().accept(this); + } - if (!this->bag.enter(name, variable_symbol)) + void resolving_visitor::visit(if_statement *statement) + { + statement->branch().prerequisite().accept(this); + for (auto *branch_statement : statement->branch().statements) { - auto original = this->bag.lookup(name); - add_error(position, name, - declaration_error::redefinition{ .original = original->position, - .file = this->redefinition_file(original) }); + branch_statement->accept(this); + } + for (conditional_statements *branch : statement->branches) + { + branch->prerequisite().accept(this); + + for (auto *branch_statement : branch->statements) + { + branch_statement->accept(this); + } + } + if (statement->alternative != nullptr) + { + for (auto *branch_statement : *statement->alternative) + { + branch_statement->accept(this); + } } - return variable_symbol; } - void name_analysis_visitor::visit(variable_declaration *declaration) + void resolving_visitor::visit(while_statement *statement) { - declaration->variable_type().accept(this); - auto variable_type = this->current_type; - std::optional computed; - - if (declaration->initializer != nullptr) + statement->branch().prerequisite().accept(this); + for (auto *branch_statement : statement->branch().statements) { - declaration->initializer->accept(this); - this->current_type = variable_type; - computed = this->constant_evaluator.evaluate(*declaration->initializer); + branch_statement->accept(this); + } + for (conditional_statements *branch : statement->branches) + { + branch->prerequisite().accept(this); - if (this->bag.is_global() && !computed.has_value()) + for (auto *branch_statement : branch->statements) { - add_error(declaration->initializer->position(), - non_constant_expression_error::initializer{ extract_identifiers(declaration->identifiers) }); + branch_statement->accept(this); } } - else if (resolve_aliases(variable_type).get() != nullptr) + } + + void resolving_visitor::visit(repeat_statement *statement) + { + statement->condition().accept(this); + for (auto *body_statement : statement->body) { - auto position_span = source_position(declaration->identifiers.front().id().position().start(), - declaration->identifiers.back().id().position().end()); - add_error(position_span, - const_qualifier_error::not_initialized{ extract_identifiers(declaration->identifiers) }); + body_statement->accept(this); } - for (const identifier_definition& variable_identifier : declaration->identifiers) + } + + void resolving_visitor::visit(defer_statement *statement) + { + for (auto *block_statement : statement->statements) { - auto variable_symbol = register_variable(variable_identifier.name(), declaration->is_extern, - declaration->position()); - variable_symbol->exported = variable_identifier.exported(); - variable_symbol->value = computed; + block_statement->accept(this); } } - void name_analysis_visitor::visit(procedure_declaration *declaration) + void resolving_visitor::visit(empty_statement *) { - std::shared_ptr info; - auto [heading, parameter_names] = build_procedure(declaration->heading()); + } - if (declaration->body.has_value()) + void resolving_visitor::visit(case_statement *statement) + { + statement->condition().accept(this); + for (const switch_case& case_block : statement->cases) { - info = std::make_shared(heading, std::move(parameter_names), this->bag.enter()); - auto name_iterator = std::cbegin(info->names); - auto type_iterator = std::cbegin(heading.parameters); - - while (name_iterator != std::cend(info->names) && type_iterator != std::cend(heading.parameters)) - { - this->current_type = *type_iterator; - auto variable_symbol = register_variable(*name_iterator, false, declaration->heading().position()); - variable_symbol->exported = false; - - ++name_iterator; - ++type_iterator; - } - for (variable_declaration *const variable : declaration->body.value().variables) - { - variable->accept(this); - } - for (statement *const statement : declaration->body.value().entry_point) + for (expression *case_label : case_block.labels) { - statement->accept(this); + case_label->accept(this); } - if (declaration->body.value().return_expression != nullptr) + for (auto *block_statement : case_block.statements) { - declaration->body.value().return_expression->accept(this); + block_statement->accept(this); } - this->bag.leave(); } - else + if (statement->alternative != nullptr) { - info = std::make_shared(heading, std::move(parameter_names)); - } - info->exported = declaration->identifier.exported(); - info->position.emplace(declaration->position()); - info->file = this->module_file; - if (!this->bag.enter(declaration->identifier.name(), info)) - { - auto original = this->bag.lookup(declaration->identifier.name()); - add_error(declaration->identifier.id().position(), declaration->identifier.name(), - declaration_error::redefinition{ .original = original->position, - .file = this->redefinition_file(original) }); + for (auto *block_statement : *statement->alternative) + { + block_statement->accept(this); + } } } - void name_analysis_visitor::visit(procedure_call *call) + void resolving_visitor::visit(procedure_call *call) { call->callable().accept(this); if (auto procedure = call->callable().type_decoration.get()) @@ -673,44 +659,76 @@ namespace elna::boot this->current_type = type(); } - void name_analysis_visitor::visit(unit *unit) + void resolving_visitor::visit(cast_expression *expression) + { + expression->value().accept(this); + expression->target().accept(this); + expression->type_decoration = this->current_type; + this->current_type = type(); + } + + void resolving_visitor::visit(record_constructor_expression *expression) + { + if (auto type_symbol = this->bag.lookup(expression->type_name.name())) + { + if (auto type_info = type_symbol->is_type()) + { + expression->type_decoration = type_info->symbol; + } + } + else + { + add_error(expression->type_name.position(), + expression->type_name.name(), declaration_error::kind::undeclared_type); + } + for (const field_initializer& initializer : expression->field_initializers) + { + initializer.value().accept(this); + if (!expression->type_decoration.empty() + && lookup_field(expression->type_decoration, initializer.name()).empty()) + { + add_error(initializer.id().position(), initializer.id().name(), + expression->type_decoration, member_error::kind::not_found); + } + } + this->current_type = type(); + } + + void resolving_visitor::visit(array_constructor_expression *expression) + { + for (auto *element : expression->elements) + { + element->accept(this); + } + const type element_type = expression->elements.front()->type_decoration; + expression->type_decoration = type(std::make_shared(element_type, + expression->elements.size())); + this->current_type = type(); + } + + void resolving_visitor::visit(slicing_expression *expression) { - for (type_declaration *const type : unit->types) - { - type->accept(this); - } - for (variable_declaration *const variable : unit->variables) + expression->base().accept(this); + auto resolved_base = resolve_underlying_type(expression->base().type_decoration); + + if (auto pointer = resolved_base.get()) { - variable->accept(this); + expression->type_decoration = type(std::make_shared(pointer->base)); } - for (procedure_declaration *const procedure : unit->procedures) + else if (auto array = resolved_base.get()) { - procedure->accept(this); + expression->type_decoration = type(std::make_shared(array->base)); } - if (unit->has_body()) + else if (auto slice = resolved_base.get()) { - this->bag.enter(); - auto variable_type = lookup_primitive_type("Int"); - auto count_symbol = std::make_shared(variable_type, false); - count_symbol->file = this->module_file; - this->bag.enter("count", count_symbol); - - variable_type = lookup_primitive_type("Word8"); - variable_type = type(std::make_shared(variable_type)); - variable_type = type(std::make_shared(variable_type)); - auto parameters_symbol = std::make_shared(variable_type, false); - parameters_symbol->file = this->module_file; - this->bag.enter("parameters", parameters_symbol); - - for (statement *const statement : unit->entry_point) - { - statement->accept(this); - } - this->bag.leave(); + expression->type_decoration = type(slice); } + expression->start().accept(this); + expression->end().accept(this); + this->current_type = type(); } - void name_analysis_visitor::visit(traits_expression *trait) + void resolving_visitor::visit(traits_expression *trait) { if (!trait->arguments.empty()) { @@ -734,9 +752,10 @@ namespace elna::boot this->current_type = type(); } - void name_analysis_visitor::visit(binary_expression *expression) + void resolving_visitor::visit(binary_expression *expression) { - walking_visitor::visit(expression); + expression->lhs().accept(this); + expression->rhs().accept(this); switch (expression->operation()) { @@ -767,9 +786,9 @@ namespace elna::boot this->current_type = type(); } - void name_analysis_visitor::visit(unary_expression *expression) + void resolving_visitor::visit(unary_expression *expression) { - walking_visitor::visit(expression); + expression->operand().accept(this); if (expression->operation() == unary_operator::reference) { @@ -783,9 +802,40 @@ namespace elna::boot this->current_type = type(); } - void name_analysis_visitor::visit(array_access_expression *expression) + void resolving_visitor::visit(named_expression *expression) + { + this->current_type = type(); + + if (auto unresolved_alias = this->bag.declared(expression->name)) + { + this->current_type = type(unresolved_alias); + } + else if (auto from_symbol_table = this->bag.lookup(expression->name)) + { + if (auto type_symbol = from_symbol_table->is_type()) + { + this->current_type = type_symbol->symbol; + } + else if (auto variable_symbol = from_symbol_table->is_variable()) + { + expression->type_decoration = variable_symbol->symbol; + } + else if (auto procedure_symbol = from_symbol_table->is_procedure()) + { + expression->type_decoration = type(std::make_shared(procedure_symbol->symbol)); + } + } + else + { + add_error(expression->position(), + expression->name, declaration_error::kind::undeclared_symbol); + } + } + + void resolving_visitor::visit(array_access_expression *expression) { - walking_visitor::visit(expression); + expression->base().accept(this); + expression->index().accept(this); auto resolved_base = resolve_underlying_type(expression->base().type_decoration); if (auto range_base = get_range_base_type(resolved_base)) @@ -800,9 +850,9 @@ namespace elna::boot this->current_type = type(); } - void name_analysis_visitor::visit(field_access_expression *expression) + void resolving_visitor::visit(field_access_expression *expression) { - walking_visitor::visit(expression); + expression->base().accept(this); // Handling field access on a type (only valid for enumerations). if (!this->current_type.empty()) @@ -845,11 +895,12 @@ namespace elna::boot expression->base().type_decoration); } } + this->current_type = type(); } - void name_analysis_visitor::visit(dereference_expression *expression) + void resolving_visitor::visit(dereference_expression *expression) { - walking_visitor::visit(expression); + expression->base().accept(this); if (auto pointer = resolve_underlying_type(expression->base().type_decoration).get()) { @@ -858,67 +909,7 @@ namespace elna::boot this->current_type = type(); } - void name_analysis_visitor::visit(for_statement *statement) - { - statement->range().accept(this); - auto resolved_range = resolve_underlying_type(statement->range().type_decoration); - const type control_variable_base_type = get_range_base_type(resolved_range); - const type control_variable_pointer_type = type(std::make_shared(control_variable_base_type)); - this->current_type = type(std::make_shared(control_variable_pointer_type)); - - statement->symbols = this->bag.enter(); - - register_variable(statement->control_variable.name(), false, statement->control_variable.position()); - if (statement->counter != nullptr) - { - this->current_type = lookup_primitive_type("Word"); - register_variable(statement->counter->name(), false, statement->counter->position()); - } - for (auto *body_statement : statement->body) - { - body_statement->accept(this); - } - this->bag.leave(); - } - - void name_analysis_visitor::visit(cast_expression *expression) - { - walking_visitor::visit(expression); - expression->type_decoration = this->current_type; - this->current_type = type(); - } - - void name_analysis_visitor::visit(named_expression *expression) - { - this->current_type = type(); - - if (auto unresolved_alias = this->bag.declared(expression->name)) - { - this->current_type = type(unresolved_alias); - } - else if (auto from_symbol_table = this->bag.lookup(expression->name)) - { - if (auto type_symbol = from_symbol_table->is_type()) - { - this->current_type = type_symbol->symbol; - } - else if (auto variable_symbol = from_symbol_table->is_variable()) - { - expression->type_decoration = variable_symbol->symbol; - } - else if (auto procedure_symbol = from_symbol_table->is_procedure()) - { - expression->type_decoration = type(std::make_shared(procedure_symbol->symbol)); - } - } - else - { - add_error(expression->position(), - expression->name, declaration_error::kind::undeclared_symbol); - } - } - - void name_analysis_visitor::visit(literal *literal) + void resolving_visitor::visit(literal *literal) { if (literal->value.is_signed()) { @@ -947,7 +938,7 @@ namespace elna::boot this->current_type = type(); } - void name_analysis_visitor::visit(literal *literal) + void resolving_visitor::visit(literal *literal) { literal->type_decoration = literal->value.format() == float_literal::format_kind::binary32 ? lookup_primitive_type("Single") @@ -955,37 +946,47 @@ namespace elna::boot this->current_type = type(); } - void name_analysis_visitor::visit(literal *literal) + void resolving_visitor::visit(literal *literal) { literal->type_decoration = lookup_primitive_type("Bool"); this->current_type = type(); } - void name_analysis_visitor::visit(literal *literal) + void resolving_visitor::visit(literal *literal) { literal->type_decoration = lookup_primitive_type("Char"); this->current_type = type(); } - void name_analysis_visitor::visit(literal *literal) + void resolving_visitor::visit(literal *literal) { literal->type_decoration = lookup_primitive_type("Pointer"); this->current_type = type(); } - void name_analysis_visitor::visit(literal *literal) + void resolving_visitor::visit(literal *literal) { literal->type_decoration = type(std::make_shared( type(std::make_shared(lookup_primitive_type("Word8"))))); this->current_type = type(); } + declaration_visitor::declaration_visitor(symbol_bag& bag, const target_info& target, + const std::filesystem::path& module_path) + : resolving_visitor(bag, target, module_path) + { + } + void declaration_visitor::visit(unit *unit) { for (type_declaration *const type : unit->types) { type->accept(this); } + for (variable_declaration *const variable : unit->variables) + { + variable->accept(this); + } for (procedure_declaration *const procedure : unit->procedures) { procedure->accept(this); @@ -994,30 +995,109 @@ namespace elna::boot void declaration_visitor::visit(type_declaration *declaration) { - const std::string& type_identifier = declaration->identifier.name(); + declaration->underlying_type().accept(this); + auto resolved = this->bag.resolve(declaration->identifier.name(), this->current_type); + auto info = std::make_shared(type(resolved)); - if (!this->unresolved.insert({ type_identifier, std::make_shared(type_identifier) }).second) + info->exported = declaration->identifier.exported(); + info->position.emplace(declaration->position()); + info->file = this->module_file; + + if (!this->bag.enter(declaration->identifier.name(), info)) { - add_error(declaration->identifier.id().position(), - declaration->identifier.id().name(), - declaration_error::redefinition{ .original = declaration->position(), .file = {} }); + auto original = this->bag.lookup(declaration->identifier.name()); + add_error(declaration->identifier.id().position(), declaration->identifier.name(), + declaration_error::redefinition{ .original = original->position, + .file = this->redefinition_file(original) }); } } void declaration_visitor::visit(procedure_declaration *declaration) { - if (!declaration->body.has_value()) + auto [heading, parameter_names] = build_procedure(declaration->heading()); + std::shared_ptr info; + + if (declaration->body.has_value()) { - return; + info = std::make_shared(heading, std::move(parameter_names), this->bag.enter()); + auto name_iterator = std::cbegin(info->names); + auto type_iterator = std::cbegin(info->symbol.parameters); + + while (name_iterator != std::cend(info->names) && type_iterator != std::cend(info->symbol.parameters)) + { + auto variable_symbol = register_variable(*name_iterator, *type_iterator, + declaration->heading().position()); + variable_symbol->exported = false; + + ++name_iterator; + ++type_iterator; + } + this->bag.leave(); } - for (variable_declaration *const variable : declaration->body.value().variables) + else { - variable->accept(this); + info = std::make_shared(heading, std::move(parameter_names)); + } + info->exported = declaration->identifier.exported(); + info->position.emplace(declaration->position()); + info->file = this->module_file; + if (!this->bag.enter(declaration->identifier.name(), info)) + { + auto original = this->bag.lookup(declaration->identifier.name()); + add_error(declaration->identifier.id().position(), declaration->identifier.name(), + declaration_error::redefinition{ .original = original->position, + .file = this->redefinition_file(original) }); + } + } + + void declaration_visitor::visit(for_statement *) + { + __builtin_unreachable(); + } + + name_analysis_visitor::name_analysis_visitor(symbol_bag& bag, const target_info& target, + const std::filesystem::path& module_path) + : resolving_visitor(bag, target, module_path) + { + } + + void name_analysis_visitor::visit(unit *unit) + { + for (procedure_declaration *const procedure : unit->procedures) + { + procedure->accept(this); + } + if (unit->has_body()) + { + this->bag.enter(); + auto variable_type = lookup_primitive_type("Int"); + auto count_symbol = std::make_shared(variable_type, false); + count_symbol->file = this->module_file; + this->bag.enter("count", count_symbol); + + variable_type = lookup_primitive_type("Word8"); + variable_type = type(std::make_shared(variable_type)); + variable_type = type(std::make_shared(variable_type)); + auto parameters_symbol = std::make_shared(variable_type, false); + parameters_symbol->file = this->module_file; + this->bag.enter("parameters", parameters_symbol); + + for (statement *const statement : unit->entry_point) + { + statement->accept(this); + } + this->bag.leave(); } } - void declaration_visitor::visit(variable_declaration *declaration) + void name_analysis_visitor::visit(type_declaration *) + { + __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()) @@ -1027,4 +1107,51 @@ namespace elna::boot } } } + + void name_analysis_visitor::visit(procedure_declaration *declaration) + { + const std::shared_ptr info = this->bag.lookup(declaration->identifier.name())->is_procedure(); + + if (declaration->body.has_value()) + { + this->bag.enter(info->scope); + for (variable_declaration *const variable : declaration->body.value().variables) + { + variable->accept(this); + } + for (statement *const statement : declaration->body.value().entry_point) + { + statement->accept(this); + } + if (declaration->body.value().return_expression != nullptr) + { + declaration->body.value().return_expression->accept(this); + } + this->bag.leave(); + } + } + + void name_analysis_visitor::visit(for_statement *statement) + { + statement->range().accept(this); + auto resolved_range = resolve_underlying_type(statement->range().type_decoration); + const type control_variable_base_type = get_range_base_type(resolved_range); + const type control_variable_pointer_type = type(std::make_shared(control_variable_base_type)); + const type control_variable_const_type = type(std::make_shared(control_variable_pointer_type)); + + statement->symbols = this->bag.enter(); + + register_variable(statement->control_variable.name(), control_variable_const_type, + statement->control_variable.position()); + if (statement->counter != nullptr) + { + register_variable(statement->counter->name(), lookup_primitive_type("Word"), + statement->counter->position()); + } + for (auto *body_statement : statement->body) + { + body_statement->accept(this); + } + this->bag.leave(); + } } -- cgit v1.2.3