diff options
| -rw-r--r-- | boot/ast.cc | 27 | ||||
| -rw-r--r-- | boot/name_analysis.cc | 48 | ||||
| -rw-r--r-- | boot/parser.yy | 17 | ||||
| -rw-r--r-- | include/elna/boot/ast.h | 12 | ||||
| -rw-r--r-- | testsuite/runnable/inferred_variable.elna | 9 |
5 files changed, 86 insertions, 27 deletions
diff --git a/boot/ast.cc b/boot/ast.cc index d698cd4..69b15d3 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -352,7 +352,10 @@ namespace elna::boot void walking_visitor::visit(variable_declaration *declaration) { - declaration->variable_type().accept(this); + if (declaration->variable_type != nullptr) + { + declaration->variable_type->accept(this); + } if (declaration->initializer != nullptr) { declaration->initializer->accept(this); @@ -895,17 +898,24 @@ namespace elna::boot } variable_declaration::variable_declaration(const source_position position, - std::vector<identifier_definition>&& identifier, std::shared_ptr<type_expression> variable_type, - expression *initializer) - : node(position), m_variable_type(std::move(variable_type)), identifiers(std::move(identifier)), initializer(initializer) + std::vector<identifier_definition>&& identifier, type_expression *variable_type, + expression *initializer, const bool is_const) + : node(position), identifiers(std::move(identifier)), variable_type(variable_type), + initializer(initializer), is_const(is_const) { } variable_declaration::variable_declaration(const source_position position, - std::vector<identifier_definition>&& identifier, std::shared_ptr<type_expression> variable_type, + std::vector<identifier_definition>&& identifier, type_expression *variable_type, std::monostate) - : node(position), m_variable_type(std::move(variable_type)), identifiers(std::move(identifier)), is_extern(true) + : node(position), identifiers(std::move(identifier)), variable_type(variable_type), + is_extern(true) + { + } + + variable_declaration::~variable_declaration() { + delete this->variable_type; } void variable_declaration::accept(parser_visitor *visitor) @@ -918,11 +928,6 @@ namespace elna::boot return this->is_extern || this->initializer != nullptr; } - type_expression& variable_declaration::variable_type() - { - return *m_variable_type; - } - procedure_type_expression::procedure_type_expression(const source_position position, std::vector<field_declaration>&& parameters, type_expression *return_type) : node(position), return_type(return_type), parameters(std::move(parameters)) diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc index 5ad2a75..c82f211 100644 --- a/boot/name_analysis.cc +++ b/boot/name_analysis.cc @@ -1447,12 +1447,24 @@ namespace elna::boot void declaration_visitor::visit(variable_declaration *declaration) { - const type variable_type = resolve_type(declaration->variable_type()); + type variable_type; std::optional<constant_value> computed; if (declaration->initializer != nullptr) { declaration->initializer->accept(this); + if (declaration->variable_type == nullptr) + { + variable_type = declaration->initializer->type_decoration; + if (declaration->is_const) + { + variable_type = type(std::make_shared<constant_type>(variable_type)); + } + } + else + { + variable_type = resolve_type(*declaration->variable_type); + } computed = this->constant_evaluator.evaluate(*declaration->initializer); if (!computed.has_value()) @@ -1461,13 +1473,21 @@ namespace elna::boot non_constant_expression_error::initializer{ extract_identifiers(declaration->identifiers) }); } } - else if (!declaration->is_extern && resolve_aliases(variable_type).get<constant_type>() != nullptr) + else { + if (declaration->variable_type != nullptr) + { + variable_type = resolve_type(*declaration->variable_type); + } + if (!declaration->is_extern && (declaration->variable_type == nullptr + || resolve_aliases(variable_type).get<constant_type>() != nullptr)) + { const source_position 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 auto& variable_identifier : declaration->identifiers) { @@ -1567,19 +1587,39 @@ namespace elna::boot { if (!this->bag.is_global()) { - const type variable_type = resolve_type(declaration->variable_type()); + type variable_type; if (declaration->initializer != nullptr) { declaration->initializer->accept(this); + if (declaration->variable_type == nullptr) + { + variable_type = declaration->initializer->type_decoration; + if (declaration->is_const) + { + variable_type = type(std::make_shared<constant_type>(variable_type)); + } + } + else + { + variable_type = resolve_type(*declaration->variable_type); + } } - else if (resolve_aliases(variable_type).get<constant_type>() != nullptr) + else { + if (declaration->variable_type != nullptr) + { + variable_type = resolve_type(*declaration->variable_type); + } + if (declaration->variable_type == nullptr + || resolve_aliases(variable_type).get<constant_type>() != nullptr) + { const source_position 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 auto& variable_identifier : declaration->identifiers) { diff --git a/boot/parser.yy b/boot/parser.yy index f416d57..cfa63d5 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -711,18 +711,23 @@ optional_identifiers: variable_declaration: identifier_definitions ":" type_expression { - std::shared_ptr<boot::type_expression> shared_type{ $3 }; - $$ = new boot::variable_declaration( boot::make_position(@$), $1, shared_type); + $$ = new boot::variable_declaration(boot::make_position(@$), $1, $3); } | identifier_definitions ":" type_expression ":=" "extern" { - std::shared_ptr<boot::type_expression> shared_type{ $3 }; - $$ = new boot::variable_declaration( boot::make_position(@$), $1, shared_type, std::monostate{}); + $$ = new boot::variable_declaration(boot::make_position(@$), $1, $3, std::monostate{}); } | identifier_definitions ":" type_expression ":=" expression { - std::shared_ptr<boot::type_expression> shared_type{ $3 }; - $$ = new boot::variable_declaration( boot::make_position(@$), $1, shared_type, $5); + $$ = new boot::variable_declaration(boot::make_position(@$), $1, $3, $5); + } + | identifier_definitions ":=" expression + { + $$ = new boot::variable_declaration(boot::make_position(@$), $1, nullptr, $3); + } + | identifier_definitions ":" "const" ":=" expression + { + $$ = new boot::variable_declaration(boot::make_position(@$), $1, nullptr, $5, true); } variable_declarations: %empty {} diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index 35cfc8d..6edeb25 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -611,24 +611,24 @@ namespace elna::boot */ class variable_declaration : public declaration { - std::shared_ptr<type_expression> m_variable_type; - public: variable_declaration(const source_position position, - std::vector<identifier_definition>&& identifier, std::shared_ptr<type_expression> variable_type, - expression *initializer = nullptr); + std::vector<identifier_definition>&& identifier, type_expression *variable_type, + expression *initializer = nullptr, const bool is_const = false); variable_declaration(const source_position position, - std::vector<identifier_definition>&& identifier, std::shared_ptr<type_expression> variable_type, + std::vector<identifier_definition>&& identifier, type_expression *variable_type, std::monostate); + ~variable_declaration() override; void accept(parser_visitor *visitor) override; bool has_initializer() const; const std::vector<identifier_definition> identifiers; - type_expression& variable_type(); + type_expression *const variable_type{ nullptr }; expression *initializer{ nullptr }; const bool is_extern{ false }; + const bool is_const{ false }; /// Whether the variable was declared in a \c threadvar section. bool is_thread_local{ false }; diff --git a/testsuite/runnable/inferred_variable.elna b/testsuite/runnable/inferred_variable.elna new file mode 100644 index 0000000..e0822b8 --- /dev/null +++ b/testsuite/runnable/inferred_variable.elna @@ -0,0 +1,9 @@ +program() +var + x := 42 + c: const := 10 + +begin + x := x + 1; + assert(x = 43 & c = 10) +end. |
