From 47521ad6d85f9bd6caee39696ce40dff82cfa50d Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Wed, 2 Sep 2026 13:31:04 +0200 Subject: Implement program entry point --- boot/name_analysis.cc | 183 +++++++++++++++++++++++++++++--------------------- 1 file changed, 108 insertions(+), 75 deletions(-) (limited to 'boot/name_analysis.cc') diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc index 3c4c6f8..77335d1 100644 --- a/boot/name_analysis.cc +++ b/boot/name_analysis.cc @@ -23,12 +23,12 @@ along with GCC; see the file COPYING3. If not see namespace elna::boot { - declaration_error::declaration_error(const source_position position, const std::string& name, payload_type payload) + symbol_declaration_error::symbol_declaration_error(const source_position position, const std::string& name, payload_type payload) : diagnostic(position), name(name), payload(std::move(payload)) { } - std::string declaration_error::what() const + std::string symbol_declaration_error::what() const { return std::visit([this](const auto& payload) -> std::string { using T = std::decay_t; @@ -57,7 +57,7 @@ namespace elna::boot }, this->payload); } - std::optional declaration_error::note() const + std::optional symbol_declaration_error::note() const { if (std::holds_alternative(this->payload)) { @@ -89,12 +89,12 @@ namespace elna::boot return message + " -> " + this->cycle.front(); } - const_qualifier_error::const_qualifier_error(const source_position position, payload_type payload) + declaration_format_error::declaration_format_error(const source_position position, payload_type payload) : diagnostic(position), payload(std::move(payload)) { } - std::string const_qualifier_error::what() const + std::string declaration_format_error::what() const { return std::visit([](const auto& payload) -> std::string { using T = std::decay_t; @@ -112,6 +112,8 @@ namespace elna::boot return "const must be written before the array size, not after"; case duplicate: return "Duplicate 'const' qualifier is not allowed"; + case module_entry: + return "Program entry point should have no or one argument"; default: __builtin_unreachable(); } @@ -119,7 +121,7 @@ namespace elna::boot }, this->payload); } - std::optional const_qualifier_error::note() const + std::optional declaration_format_error::note() const { if (std::holds_alternative(this->payload)) { @@ -256,9 +258,9 @@ namespace elna::boot if (!this->unresolved.insert({ type_identifier, std::make_shared(type_identifier) }).second) { - add_error(declaration->identifier.id().position(), + add_error(declaration->identifier.id().position(), declaration->identifier.id().name(), - declaration_error::redefinition{ .original = declaration->position(), .file = {} }); + symbol_declaration_error::redefinition{ .original = declaration->position(), .file = {} }); } } @@ -272,24 +274,28 @@ namespace elna::boot { } - std::pair> resolving_visitor::build_procedure( - procedure_type_expression& expression) + procedure_type::return_t resolving_visitor::build_return_type( + const procedure_type_expression::return_t& return_type) { - procedure_type::return_t result_return; - - if (expression.return_type.no_return) + if (return_type.no_return) { - result_return = procedure_type::return_t(std::monostate{}); + return procedure_type::return_t(std::monostate{}); } - else if (expression.return_type.proper_type != nullptr) + else if (return_type.proper_type != nullptr) { - expression.return_type.proper_type->accept(this); - result_return = procedure_type::return_t(this->current_type); + return_type.proper_type->accept(this); + return procedure_type::return_t(this->current_type); } else { - result_return = procedure_type::return_t(); + return procedure_type::return_t(); } + } + + std::pair> resolving_visitor::build_procedure( + procedure_type_expression& expression) + { + const procedure_type::return_t result_return = build_return_type(expression.return_type); std::pair> result_type{ procedure_type(result_return), std::vector() }; @@ -361,9 +367,11 @@ namespace elna::boot 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) }); + symbol_declaration_error::redefinition original_definition{ + .original = original->position, + .file = this->redefinition_file(original) + }; + add_error(position, name, original_definition); } return variable_symbol; } @@ -424,8 +432,8 @@ namespace elna::boot { 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) }); + add_error(position_span, + declaration_format_error::not_initialized{ extract_identifiers(declaration->identifiers) }); } for (const identifier_definition& variable_identifier : declaration->identifiers) { @@ -443,8 +451,8 @@ namespace elna::boot if (array_base.get() != nullptr) { - add_error(expression->position(), - const_qualifier_error::kind::array_position); + add_error(expression->position(), + declaration_format_error::kind::array_position); } expression->dimensions().accept(this); if (expression->dimensions().type_decoration.empty()) @@ -483,8 +491,8 @@ namespace elna::boot expression->base().accept(this); if (this->current_type.get() != nullptr) { - add_error(expression->position(), - const_qualifier_error::kind::duplicate); + add_error(expression->position(), + declaration_format_error::kind::duplicate); } this->current_type = type(std::make_shared(this->current_type)); } @@ -512,8 +520,8 @@ namespace elna::boot } else { - add_error(expression->base.value().position(), - expression->base.value().name(), declaration_error::kind::undeclared_type); + add_error(expression->base.value().position(), + expression->base.value().name(), symbol_declaration_error::kind::undeclared_type); this->current_type = type(); return; } @@ -698,8 +706,8 @@ namespace elna::boot } else { - add_error(expression->type_name.position(), - expression->type_name.name(), declaration_error::kind::undeclared_type); + add_error(expression->type_name.position(), + expression->type_name.name(), symbol_declaration_error::kind::undeclared_type); } for (const field_initializer& initializer : expression->field_initializers) { @@ -766,8 +774,8 @@ namespace elna::boot } else { - add_error(trait->name.position(), - trait->name.name(), declaration_error::kind::undeclared_trait); + add_error(trait->name.position(), + trait->name.name(), symbol_declaration_error::kind::undeclared_trait); } this->current_type = type(); } @@ -847,8 +855,8 @@ namespace elna::boot } else { - add_error(expression->position(), - expression->name, declaration_error::kind::undeclared_symbol); + add_error(expression->position(), + expression->name, symbol_declaration_error::kind::undeclared_symbol); } } @@ -1112,6 +1120,49 @@ namespace elna::boot { procedure->accept(this); } + if (unit->entry_point.has_value()) + { + auto word8_primitive = lookup_primitive_type("Word8"); + const procedure_type::return_t result_return = procedure_type::return_t(word8_primitive); + auto heading = procedure_type(result_return); + std::shared_ptr info; + + if (unit->parameters.size() > 1) + { + add_error(unit->position(), + declaration_format_error::kind::module_entry); + } + else if (unit->parameters.size() == 1) + { + auto variable_type = type(std::make_shared(word8_primitive)); + variable_type = type(std::make_shared(variable_type)); + + heading.parameters.push_back(variable_type); + + info = std::make_shared(heading, + std::vector({ unit->parameters.at(0).name() }), this->bag.enter()); + + register_variable(info->names.at(0), variable_type, unit->parameters.at(0).position()); + } + else + { + info = std::make_shared(heading, std::vector{}, this->bag.enter()); + } + this->bag.leave(); + + info->position.emplace(unit->position()); + info->file = this->module_file; + + if (!this->bag.enter("", info)) + { + auto original = this->bag.lookup(""); + symbol_declaration_error::redefinition original_definition{ + .original = original->position, + .file = this->redefinition_file(original) + }; + add_error(unit->position(), "program", original_definition); + } + } } void declaration_visitor::visit(type_declaration *declaration) @@ -1138,9 +1189,12 @@ namespace elna::boot 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) }); + symbol_declaration_error::redefinition original_definition{ + .original = original->position, + .file = this->redefinition_file(original) + }; + add_error(declaration->identifier.id().position(), + declaration->identifier.name(), original_definition); } } @@ -1159,7 +1213,6 @@ namespace elna::boot { auto variable_symbol = register_variable(*name_iterator, *type_iterator, declaration->heading().position()); - variable_symbol->exported = false; ++name_iterator; ++type_iterator; @@ -1176,9 +1229,12 @@ namespace elna::boot 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) }); + symbol_declaration_error::redefinition original_definition{ + .original = original->position, + .file = this->redefinition_file(original) + }; + add_error(declaration->identifier.id().position(), + declaration->identifier.name(), original_definition); } } @@ -1199,25 +1255,12 @@ namespace elna::boot { procedure->accept(this); } - if (unit->has_body()) + if (unit->entry_point.has_value()) { - 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); + const std::shared_ptr info = this->bag.lookup("")->is_procedure(); - for (statement *const statement : unit->entry_point) - { - statement->accept(this); - } + this->bag.enter(info->scope); + traverse_body(this, unit->entry_point.value()); this->bag.leave(); } } @@ -1234,31 +1277,21 @@ namespace elna::boot { if (variable_identifier.exported()) { - add_error(variable_identifier.id().position(), - variable_identifier.id().name(), declaration_error::kind::local_export); + add_error(variable_identifier.id().position(), + variable_identifier.id().name(), symbol_declaration_error::kind::local_export); } } } 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()) { + const std::shared_ptr info = + this->bag.lookup(declaration->identifier.name())->is_procedure(); + 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); - } + traverse_body(this, declaration->body.value()); this->bag.leave(); } } -- cgit v1.2.3