aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-10-08 01:46:45 +0200
committerEugen Wissner <belka@caraus.de>2026-10-08 01:46:45 +0200
commitd392f0c54a7748b816ab327758ae835f73cd1c0a (patch)
treea7c029dffab842acbd4f5f0cab5685a93e9b9747
parentd4b7f5e52a33f2d15aafca7f1b040f3f2821fd0c (diff)
downloadelna-d392f0c54a7748b816ab327758ae835f73cd1c0a.tar.gz
Allow initialized declarations without an explicit type
-rw-r--r--boot/ast.cc27
-rw-r--r--boot/name_analysis.cc48
-rw-r--r--boot/parser.yy17
-rw-r--r--include/elna/boot/ast.h12
-rw-r--r--testsuite/runnable/inferred_variable.elna9
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.