aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-10-09 23:35:03 +0200
committerEugen Wissner <belka@caraus.de>2026-10-09 23:35:03 +0200
commitda1e84e33de1a9c2cc1745b8f42bc7f0cee8fc5c (patch)
tree6222ecd61c9d6e9d59c6169b99e4a24a5d347fea /boot
parent134d3ac4caff6d87c79b0892e57073594cb0064c (diff)
downloadelna-da1e84e33de1a9c2cc1745b8f42bc7f0cee8fc5c.tar.gz
Add const sections
Diffstat (limited to 'boot')
-rw-r--r--boot/ast.cc41
-rw-r--r--boot/evaluator.cc4
-rw-r--r--boot/materialization.cc17
-rw-r--r--boot/name_analysis.cc69
-rw-r--r--boot/parser.yy56
-rw-r--r--boot/symbol.cc15
-rw-r--r--boot/validation.cc4
7 files changed, 203 insertions, 3 deletions
diff --git a/boot/ast.cc b/boot/ast.cc
index edc10a7..15e4928 100644
--- a/boot/ast.cc
+++ b/boot/ast.cc
@@ -72,6 +72,11 @@ namespace elna::boot
__builtin_unreachable();
}
+ void empty_visitor::visit(constant_declaration *)
+ {
+ __builtin_unreachable();
+ }
+
void empty_visitor::visit(procedure_declaration *)
{
__builtin_unreachable();
@@ -357,6 +362,11 @@ namespace elna::boot
}
}
+ void walking_visitor::visit(constant_declaration *declaration)
+ {
+ declaration->initializer->accept(this);
+ }
+
void walking_visitor::visit(array_type_expression *expression)
{
expression->base().accept(this);
@@ -1007,6 +1017,31 @@ namespace elna::boot
return *m_underlying_type;
}
+ constant_declaration::constant_declaration(const source_position position,
+ identifier_definition identifier, expression *const initializer)
+ : node(position), identifier(std::move(identifier)), initializer(initializer)
+ {
+ }
+
+ constant_declaration::~constant_declaration()
+ {
+ delete this->initializer;
+ }
+
+ void constant_declaration::accept(parser_visitor *visitor)
+ {
+ visitor->visit(this);
+ }
+
+ block::block(std::vector<constant_declaration *>&& constants,
+ std::vector<variable_declaration *>&& variables,
+ std::vector<statement *>&& statements)
+ : constants(std::move(constants)),
+ variables(std::move(variables)),
+ statements(std::move(statements))
+ {
+ }
+
block::block(std::vector<variable_declaration *>&& variables, std::vector<statement *>&& statements)
: variables(std::move(variables)), statements(std::move(statements))
{
@@ -1014,6 +1049,7 @@ namespace elna::boot
block& block::operator=(block&& that) noexcept
{
+ std::swap(this->constants, that.constants);
std::swap(this->variables, that.variables);
std::swap(this->statements, that.statements);
std::swap(this->symbols, that.symbols);
@@ -1031,6 +1067,10 @@ namespace elna::boot
{
delete variable;
}
+ for (const constant_declaration *constant : this->constants)
+ {
+ delete constant;
+ }
}
procedure_body::procedure_body(block&& body, expression *return_expression)
@@ -1059,6 +1099,7 @@ namespace elna::boot
void traverse_block(parser_visitor *visitor, const block& body)
{
+ visit_all(visitor, body.constants);
visit_all(visitor, body.variables);
visit_all(visitor, body.statements);
}
diff --git a/boot/evaluator.cc b/boot/evaluator.cc
index 78eb4cd..a96d8ab 100644
--- a/boot/evaluator.cc
+++ b/boot/evaluator.cc
@@ -295,6 +295,10 @@ namespace elna::boot
{
return std::nullopt;
}
+ if (const std::shared_ptr<constant_info> constant = symbol->is_constant())
+ {
+ return constant->value;
+ }
const std::shared_ptr<variable_info> variable = symbol->is_variable();
if (variable == nullptr
diff --git a/boot/materialization.cc b/boot/materialization.cc
index c7296f9..fd2558b 100644
--- a/boot/materialization.cc
+++ b/boot/materialization.cc
@@ -39,6 +39,8 @@ namespace elna::boot
return "Local symbols cannot be extern";
case variable_generic:
return "Variables cannot have generic parameters";
+ case constant_generic:
+ return "Constants cannot have generic parameters";
}
__builtin_unreachable();
}
@@ -91,6 +93,21 @@ namespace elna::boot
}
}
+ void materialization_visitor::visit(constant_declaration *declaration)
+ {
+ walking_visitor::visit(declaration);
+ if (!this->in_global_scope && declaration->identifier.exported())
+ {
+ add_error<materialization_error>(declaration->identifier.id().position(),
+ materialization_error::kind::local_export);
+ }
+ if (!declaration->identifier.parameters.empty())
+ {
+ add_error<materialization_error>(declaration->identifier.id().position(),
+ materialization_error::kind::constant_generic);
+ }
+ }
+
void materialization_visitor::visit(literal<integer_literal> *literal)
{
switch (literal->wants_signed)
diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc
index 9b3dec4..36faee1 100644
--- a/boot/name_analysis.cc
+++ b/boot/name_analysis.cc
@@ -317,6 +317,10 @@ namespace elna::boot
{
}
+ void forward_declaration_visitor::visit(constant_declaration *)
+ {
+ }
+
void forward_declaration_visitor::visit(procedure_declaration *)
{
}
@@ -449,6 +453,26 @@ namespace elna::boot
return variable_symbol;
}
+ std::shared_ptr<constant_info> resolving_visitor::register_constant(const std::string& name,
+ const type& constant_type, const constant_value& value, const source_position position)
+ {
+ const std::shared_ptr<constant_info> constant_symbol =
+ std::make_shared<constant_info>(constant_type, value);
+ constant_symbol->position.emplace(position);
+ constant_symbol->file = this->module_file;
+
+ if (!this->bag.enter(name, constant_symbol))
+ {
+ const std::shared_ptr<info> original = this->bag.lookup(name);
+ symbol_declaration_error::redefinition original_definition{
+ .original = original->position,
+ .file = this->redefinition_file(original)
+ };
+ add_error<symbol_declaration_error>(position, name, original_definition);
+ }
+ return constant_symbol;
+ }
+
std::optional<type> resolving_visitor::lookup_pointer_like_field(
const std::string& field_name, const type& element_type)
{
@@ -1063,6 +1087,10 @@ namespace elna::boot
{
expression->type_decoration = variable_symbol->symbol;
}
+ else if (const auto constant_symbol = from_symbol_table->is_constant())
+ {
+ expression->type_decoration = constant_symbol->symbol;
+ }
else if (const auto procedure_symbol = from_symbol_table->is_procedure())
{
type procedure = type(std::make_shared<procedure_type>(procedure_symbol->symbol));
@@ -1502,6 +1530,25 @@ namespace elna::boot
}
}
+ void declaration_visitor::visit(constant_declaration *declaration)
+ {
+ declaration->initializer->accept(this);
+ const std::optional<constant_value> computed =
+ this->constant_evaluator.evaluate(*declaration->initializer);
+ if (!computed.has_value())
+ {
+ const non_constant_expression_error::initializer payload{ { declaration->identifier.id() } };
+ add_error<non_constant_expression_error>(declaration->initializer->position(), payload);
+ return;
+ }
+ const type constant_type = declaration->initializer->type_decoration;
+ const source_position position = declaration->position();
+ const std::string name = declaration->identifier.name();
+ const std::shared_ptr<constant_info> constant_symbol =
+ register_constant(name, constant_type, computed.value(), position);
+ constant_symbol->exported = declaration->identifier.exported();
+ }
+
void declaration_visitor::visit(procedure_declaration *declaration)
{
// The scope is opened before the heading is built so that the type
@@ -1633,6 +1680,28 @@ namespace elna::boot
}
}
+ void name_analysis_visitor::visit(constant_declaration *declaration)
+ {
+ if (!this->bag.is_global())
+ {
+ declaration->initializer->accept(this);
+ const std::optional<constant_value> computed =
+ this->constant_evaluator.evaluate(*declaration->initializer);
+ if (!computed.has_value())
+ {
+ const non_constant_expression_error::initializer payload{ { declaration->identifier.id() } };
+ add_error<non_constant_expression_error>(declaration->initializer->position(), payload);
+ return;
+ }
+ const type constant_type = declaration->initializer->type_decoration;
+ const source_position position = declaration->position();
+ const std::string name = declaration->identifier.name();
+ const std::shared_ptr<constant_info> constant_symbol =
+ register_constant(name, constant_type, computed.value(), position);
+ constant_symbol->exported = declaration->identifier.exported();
+ }
+ }
+
void name_analysis_visitor::visit(procedure_declaration *declaration)
{
if (declaration->body.has_value())
diff --git a/boot/parser.yy b/boot/parser.yy
index 9628443..fa701ec 100644
--- a/boot/parser.yy
+++ b/boot/parser.yy
@@ -132,6 +132,10 @@ along with GCC; see the file COPYING3. If not see
%type <std::vector<elna::boot::switch_case>> switch_cases;
%type <elna::boot::variable_declaration *> variable_declaration;
%type <std::vector<elna::boot::variable_declaration *>> variable_declarations;
+%type <elna::boot::constant_declaration *> const_declaration;
+%type <std::vector<elna::boot::constant_declaration *>> const_declarations;
+%type <std::pair<std::vector<elna::boot::constant_declaration *>, std::vector<elna::boot::variable_declaration *>>>
+ block_declaration block_declarations;
%type <elna::boot::type_expression *> type_expression return_declaration;
%type <std::vector<elna::boot::type_expression *>> type_expressions;
%type <elna::boot::expression *> expression operand simple_expression procedure_return unary_expression;
@@ -201,6 +205,12 @@ section:
$$.insert($$.end(), variables.begin(), variables.end());
}
+ | "const" const_declarations
+ {
+ std::vector<boot::constant_declaration *> constants = $2;
+
+ $$.insert($$.end(), constants.begin(), constants.end());
+ }
| "threadvar" variable_declarations
{
std::vector<boot::variable_declaration *> variables = $2;
@@ -231,11 +241,39 @@ sections:
procedure_body:
block procedure_return
{ $$ = std::make_unique<boot::procedure_body>(std::move(*$1), $2); }
+block_declaration:
+ "const" const_declarations
+ {
+ $$ = { std::move($2), {} };
+ }
+ | "var" variable_declarations
+ {
+ $$ = { {}, std::move($2) };
+ }
+block_declarations:
+ block_declaration block_declarations
+ {
+ auto [constants, variables] = std::move($1);
+ auto [more_constants, more_variables] = std::move($2);
+
+ constants.insert(constants.end(), more_constants.begin(), more_constants.end());
+ variables.insert(variables.end(), more_variables.begin(), more_variables.end());
+ $$ = { std::move(constants), std::move(variables) };
+ }
+ | block_declaration
+ {
+ $$ = std::move($1);
+ }
block:
- "var" variable_declarations statement_part
- { $$ = std::make_unique<boot::block>($2, $3); }
+ block_declarations statement_part
+ {
+ auto [constants, variables] = std::move($1);
+ $$ = std::make_unique<boot::block>(std::move(constants), std::move(variables), $2);
+ }
| optional_begin_statements
- { $$ = std::make_unique<boot::block>(std::vector<boot::variable_declaration *>(), $1); }
+ {
+ $$ = std::make_unique<boot::block>(std::vector<boot::variable_declaration *>(), $1);
+ }
statement_part:
%empty {}
| "begin" statements { $$ = $2; }
@@ -749,6 +787,18 @@ variable_declarations:
$$ = $2;
$$.insert(std::cbegin($$), $1);
}
+const_declaration:
+ identifier_definition "=" expression
+ {
+ $$ = new boot::constant_declaration(boot::make_position(@$), std::move(*$1), $3);
+ }
+const_declarations:
+ %empty {}
+ | const_declaration const_declarations
+ {
+ $$ = $2;
+ $$.insert(std::cbegin($$), $1);
+ }
import_path:
IDENTIFIER "." import_path
{
diff --git a/boot/symbol.cc b/boot/symbol.cc
index ffefea4..8feba4a 100644
--- a/boot/symbol.cc
+++ b/boot/symbol.cc
@@ -326,6 +326,11 @@ namespace elna::boot
return nullptr;
}
+ std::shared_ptr<constant_info> info::is_constant()
+ {
+ return nullptr;
+ }
+
type_info::type_info(const type& symbol)
: symbol(symbol), owner(symbol.get<alias_type>())
{
@@ -362,6 +367,16 @@ namespace elna::boot
return std::static_pointer_cast<variable_info>(shared_from_this());
}
+ constant_info::constant_info(const type& symbol, const constant_value& value)
+ : symbol(symbol), value(value)
+ {
+ }
+
+ std::shared_ptr<constant_info> constant_info::is_constant()
+ {
+ return std::static_pointer_cast<constant_info>(shared_from_this());
+ }
+
label_info::label_info(std::size_t defer_depth)
: defer_depth(defer_depth)
{
diff --git a/boot/validation.cc b/boot/validation.cc
index 4539633..aa47557 100644
--- a/boot/validation.cc
+++ b/boot/validation.cc
@@ -73,6 +73,10 @@ namespace elna::boot
{
}
+ void validation_visitor::visit(constant_declaration *)
+ {
+ }
+
void validation_visitor::visit(procedure_declaration *declaration)
{
if (declaration->body.has_value())