aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-rw-r--r--boot/ast.cc12
-rw-r--r--boot/driver.cc25
-rw-r--r--boot/evaluator.cc58
-rw-r--r--boot/lexer.ll5
-rw-r--r--boot/name_analysis.cc166
-rw-r--r--boot/parser.yy81
-rw-r--r--boot/result.cc10
-rw-r--r--boot/symbol.cc112
-rw-r--r--boot/type_check.cc197
-rw-r--r--boot/validation.cc8
10 files changed, 351 insertions, 323 deletions
diff --git a/boot/ast.cc b/boot/ast.cc
index b38e8d1..2d8e90d 100644
--- a/boot/ast.cc
+++ b/boot/ast.cc
@@ -367,7 +367,10 @@ namespace elna::boot
void walking_visitor::visit_entry_point(unit *unit)
{
- traverse_body(this, unit->entry_point.value());
+ for (statement *body_statement : unit->entry_point.value())
+ {
+ body_statement->accept(this);
+ }
}
void walking_visitor::visit(type_declaration *declaration)
@@ -1121,10 +1124,9 @@ namespace elna::boot
std::vector<declaration *>&& declarations,
std::vector<identifier>&& parameters,
const source_position entry_position,
- std::optional<procedure_body>&& body)
- : node(position),
- imports(std::move(imports)), declarations(std::move(declarations)), entry_point(std::move(body)),
- parameters(std::move(parameters)), entry_position(entry_position)
+ std::vector<statement *>&& body)
+ : node(position), imports(std::move(imports)), declarations(std::move(declarations)),
+ entry_point(std::move(body)), parameters(std::move(parameters)), entry_position(entry_position)
{
}
diff --git a/boot/driver.cc b/boot/driver.cc
index 2bcbcb1..14575f7 100644
--- a/boot/driver.cc
+++ b/boot/driver.cc
@@ -23,9 +23,9 @@ namespace elna::boot
{
source_position make_position(const yy::location& location)
{
- auto start_location = boot::location(static_cast<std::size_t>(location.begin.line),
+ const boot::location start_location = boot::location(static_cast<std::size_t>(location.begin.line),
static_cast<std::size_t>(location.begin.column));
- auto end_location = boot::location(static_cast<std::size_t>(location.end.line),
+ const boot::location end_location = boot::location(static_cast<std::size_t>(location.end.line),
static_cast<std::size_t>(location.end.column));
return source_position(start_location, end_location);
@@ -41,6 +41,11 @@ namespace elna::boot
return message;
}
+ bool driver::has_finished() const
+ {
+ return this->tree != nullptr;
+ }
+
static char unescape_character(char escape)
{
switch (escape)
@@ -79,19 +84,19 @@ namespace elna::boot
constexpr unsigned char utf8_lead_tag_3byte = 0xE0;
constexpr unsigned char utf8_lead_tag_4byte = 0xF0;
- constexpr int utf8_continuation_bits = 6;
- constexpr uint32_t utf8_continuation_mask = 0x3F;
+ constexpr std::uint32_t utf8_continuation_bits = 6;
+ constexpr std::uint32_t utf8_continuation_mask = 0x3F;
constexpr unsigned char utf8_continuation_tag = 0x80;
- constexpr uint32_t utf8_surrogate_range_start = 0xD800;
- constexpr uint32_t utf8_surrogate_range_end = 0xDFFF;
- constexpr uint32_t utf8_max_unicode_codepoint = 0x10FFFF;
+ constexpr std::uint32_t utf8_surrogate_range_start = 0xD800;
+ constexpr std::uint32_t utf8_surrogate_range_end = 0xDFFF;
+ constexpr std::uint32_t utf8_max_unicode_codepoint = 0x10FFFF;
static std::optional<std::string> encode_utf8(uint32_t codepoint)
{
- constexpr uint32_t utf8_1byte_max = 0x80;
- constexpr uint32_t utf8_2byte_max = 0x800;
- constexpr uint32_t utf8_3byte_max = 0x10000;
+ constexpr std::uint32_t utf8_1byte_max = 0x80;
+ constexpr std::uint32_t utf8_2byte_max = 0x800;
+ constexpr std::uint32_t utf8_3byte_max = 0x10000;
std::string result;
diff --git a/boot/evaluator.cc b/boot/evaluator.cc
index 0085c62..6cf287c 100644
--- a/boot/evaluator.cc
+++ b/boot/evaluator.cc
@@ -66,7 +66,7 @@ namespace elna::boot
std::optional<type_properties> get_type_properties(const type& subject, const target_info& target)
{
- auto resolved = resolve_underlying_type(subject);
+ const type resolved = resolve_underlying_type(subject);
if (resolved.get<enumeration_type>() != nullptr)
{
@@ -78,7 +78,7 @@ namespace elna::boot
return erased.empty() ? std::nullopt : get_type_properties(erased, target);
}
- else if (auto resolved_primitive = resolved.get<primitive_type>())
+ else if (const auto resolved_primitive = resolved.get<primitive_type>())
{
return resolved_primitive->properties;
}
@@ -93,7 +93,7 @@ namespace elna::boot
{
return target.pointer_properties;
}
- else if (auto array = resolved.get<array_type>())
+ else if (const auto array = resolved.get<array_type>())
{
if (auto element = get_type_properties(array->base, target))
{
@@ -103,7 +103,7 @@ namespace elna::boot
};
}
}
- else if (auto record = resolved.get<record_type>())
+ else if (const auto record = resolved.get<record_type>())
{
auto record_layout = layout_record(record, target);
if (record_layout.has_value())
@@ -212,7 +212,7 @@ namespace elna::boot
{
return evaluate_traits(*traits);
}
- else if (auto *record_constructor = subject.is_record_constructor())
+ else if (const auto *record_constructor = subject.is_record_constructor())
{
ordered_map<constant_value> aggregate;
@@ -227,7 +227,7 @@ namespace elna::boot
}
return constant_value{ constant_aggregate<ordered_map>{ std::move(aggregate) } };
}
- else if (auto *array_constructor = subject.is_array_constructor())
+ else if (const auto *array_constructor = subject.is_array_constructor())
{
std::vector<constant_value> elements;
for (expression *element : array_constructor->elements)
@@ -275,13 +275,13 @@ namespace elna::boot
std::optional<constant_value> evaluator::evaluate_named(named_expression& subject)
{
- auto symbol = this->bag.lookup(subject.name);
+ const std::shared_ptr<info> symbol = this->bag.lookup(subject.name);
if (symbol == nullptr)
{
return std::nullopt;
}
- auto variable = symbol->is_variable();
+ const std::shared_ptr<variable_info> variable = symbol->is_variable();
if (variable == nullptr
|| resolve_aliases(variable->symbol).get<constant_type>() == nullptr)
@@ -315,17 +315,17 @@ namespace elna::boot
// reading the type decoration set by name analysis.
if (auto *base_designator = subject.base().is_designator())
{
- if (auto *base_name = base_designator->is_named())
+ if (const auto *base_name = base_designator->is_named())
{
- auto symbol = this->bag.lookup(base_name->name);
+ const std::shared_ptr<info> symbol = this->bag.lookup(base_name->name);
if (symbol != nullptr)
{
- if (auto type_symbol = symbol->is_type())
+ if (const auto type_symbol = symbol->is_type())
{
- if (auto enumeration = resolve_underlying_type(type_symbol->symbol).get<enumeration_type>())
+ if (const auto enumeration = resolve_underlying_type(type_symbol->symbol).get<enumeration_type>())
{
- auto member_iterator = std::ranges::find(enumeration->members, subject.field().name());
+ const auto member_iterator = std::ranges::find(enumeration->members, subject.field().name());
if (member_iterator == enumeration->members.end())
{
@@ -344,7 +344,7 @@ namespace elna::boot
{
if (auto *record = std::get_if<constant_aggregate<ordered_map>>(&base.value()))
{
- auto field_iterator = (*record)->find(subject.field().name());
+ const auto field_iterator = (*record)->find(subject.field().name());
return field_iterator != std::cend(**record)
? std::make_optional(field_iterator->second)
@@ -355,7 +355,7 @@ namespace elna::boot
{
return constant_value{ integer_literal::from((*vector)->size()) };
}
- else if (auto *string_value = std::get_if<std::string>(&base.value()); subject.field() == "length")
+ else if (const auto *string_value = std::get_if<std::string>(&base.value()); subject.field() == "length")
{
return constant_value{ integer_literal::from(string_value->size()) };
}
@@ -370,7 +370,7 @@ namespace elna::boot
{
return std::nullopt;
}
- auto& index_literal = std::get<integer_literal>(evaluated_index.value());
+ const integer_literal& index_literal = std::get<integer_literal>(evaluated_index.value());
return index_literal < 0 ? std::nullopt : index_literal.try_to<std::size_t>();
}
@@ -389,8 +389,8 @@ namespace elna::boot
{
return std::nullopt;
}
- auto slice_begin = std::next((*array)->begin(), static_cast<std::ptrdiff_t>(start_index.value() - 1));
- auto slice_end = std::next((*array)->begin(), static_cast<std::ptrdiff_t>(end_index.value()));
+ const auto slice_begin = std::next((*array)->begin(), static_cast<std::ptrdiff_t>(start_index.value() - 1));
+ const auto slice_end = std::next((*array)->begin(), static_cast<std::ptrdiff_t>(end_index.value()));
return constant_value{
constant_aggregate<std::vector>{ std::vector<constant_value>(slice_begin, slice_end) }
@@ -687,7 +687,7 @@ namespace elna::boot
}
return std::visit([&rhs, operation = subject.operation()](auto&& lhs_value) {
using T = std::decay_t<decltype(lhs_value)>;
- auto rhs_value = std::get<T>(rhs.value());
+ const T rhs_value = std::get<T>(rhs.value());
return evaluate_operation<T>(operation, lhs_value, rhs_value);
}, lhs.value());
@@ -921,13 +921,11 @@ namespace elna::boot
{
return source_expression;
}
- if (const auto *address = std::get_if<integer_literal>(&source_expression))
+ // Only the null pointer has a constant representation.
+ else if (const auto *address = std::get_if<integer_literal>(&source_expression);
+ *address == std::ptrdiff_t{ 0 })
{
- // Only the null pointer has a constant representation.
- if (*address == std::ptrdiff_t{ 0 })
- {
- return constant_value{ nullptr };
- }
+ return constant_value{ nullptr };
}
return std::nullopt;
}
@@ -1056,7 +1054,7 @@ namespace elna::boot
{
return constant_value{ float_literal::from(std::numeric_limits<double>::min()) };
}
- if (auto enumeration = resolved.get<enumeration_type>())
+ if (const auto enumeration = resolved.get<enumeration_type>())
{
return constant_value{ integer_literal::from<std::size_t>(1) };
}
@@ -1101,22 +1099,22 @@ namespace elna::boot
{
return constant_value{ float_literal::from(std::numeric_limits<double>::max()) };
}
- if (auto enumeration = resolved.get<enumeration_type>())
+ if (const auto enumeration = resolved.get<enumeration_type>())
{
return constant_value{ integer_literal::from(enumeration->members.size()) };
}
}
else if (subject.name.name() == "offset")
{
- auto *field = subject.arguments.at(1)->is_named();
- auto record = erase_generic(subject.types.front()).get<record_type>();
+ const named_expression *field = subject.arguments.at(1)->is_named();
+ const std::shared_ptr<record_type> record = erase_generic(subject.types.front()).get<record_type>();
if (field == nullptr || record == nullptr)
{
return std::nullopt;
}
if (auto record_layout = layout_record(record, this->target))
{
- auto field_search = record_layout.value().offset_map.find(field->name);
+ const auto field_search = record_layout.value().offset_map.find(field->name);
if (field_search != std::cend(record_layout.value().offset_map))
{
diff --git a/boot/lexer.ll b/boot/lexer.ll
index 3d881e3..6fa1904 100644
--- a/boot/lexer.ll
+++ b/boot/lexer.ll
@@ -55,7 +55,7 @@ EXPONENT [eE][+-]?[[:digit:]]+
%%
%{
- if (driver.finished)
+ if (driver.has_finished())
{
return yy::parser::make_YYEOF(this->location);
}
@@ -197,6 +197,9 @@ to {
program {
return yy::parser::make_PROGRAM(this->location);
}
+module {
+ return yy::parser::make_MODULE(this->location);
+}
{ID1}{ID2}* {
return yy::parser::make_IDENTIFIER(yytext, this->location);
}
diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc
index 18aaca2..5d5bd34 100644
--- a/boot/name_analysis.cc
+++ b/boot/name_analysis.cc
@@ -195,7 +195,7 @@ namespace elna::boot
if (is_enum || is_record)
{
std::string message = is_enum ? "Enumeration" : "Record";
- if (auto alias = this->composite.get<alias_type>())
+ if (const auto alias = this->composite.get<alias_type>())
{
message += " '" + alias->name + "'";
}
@@ -220,7 +220,7 @@ namespace elna::boot
const std::string kind = is_enum ? "member" : "field";
std::string message = is_enum ? "Enumeration" : "Record";
- if (auto alias = this->composite.get<alias_type>())
+ if (const auto alias = this->composite.get<alias_type>())
{
message += " '" + alias->name + "'";
}
@@ -267,7 +267,7 @@ namespace elna::boot
static void collect_field_names(const type& composite_type,
ordered_map<field_origin>& names)
{
- auto record = erase_generic(composite_type).get<record_type>();
+ const std::shared_ptr<record_type> record = erase_generic(composite_type).get<record_type>();
if (record == nullptr)
{
return;
@@ -276,7 +276,7 @@ namespace elna::boot
{
collect_field_names(record->base, names);
}
- for (auto& field : record->fields)
+ for (const auto& field : record->fields)
{
names.insert(field.first, field_origin{ .position = std::nullopt, .base_type = composite_type });
}
@@ -435,7 +435,7 @@ namespace elna::boot
if (!existing->second.position.has_value()
&& !existing->second.base_type.empty())
{
- if (auto alias = existing->second.base_type.get<alias_type>())
+ if (const auto alias = existing->second.base_type.get<alias_type>())
{
base_name = alias->name;
}
@@ -471,7 +471,7 @@ namespace elna::boot
if (!this->bag.enter(name, variable_symbol))
{
- auto original = this->bag.lookup(name);
+ const std::shared_ptr<info> original = this->bag.lookup(name);
symbol_declaration_error::redefinition original_definition{
.original = original->position,
.file = this->redefinition_file(original)
@@ -490,7 +490,7 @@ namespace elna::boot
}
if (field_name == "ptr")
{
- auto pointer = type(std::make_shared<pointer_type>(element_type));
+ const type pointer = type(std::make_shared<pointer_type>(element_type));
return type(std::make_shared<constant_type>(pointer));
}
return std::nullopt;
@@ -506,9 +506,9 @@ namespace elna::boot
}
const type resolved_type = resolve_underlying_type(composite_type);
- if (auto range_base = get_range_base_type(resolved_type))
+ if (const auto range_base = get_range_base_type(resolved_type))
{
- if (auto field = lookup_pointer_like_field(field_name, range_base))
+ if (const auto field = lookup_pointer_like_field(field_name, range_base))
{
return field.value();
}
@@ -524,18 +524,18 @@ namespace elna::boot
for (const identifier& parameter : parameters)
{
const type parameter_symbol = type(std::make_shared<parameter_type>(parameter.name()));
- auto info = std::make_shared<type_info>(parameter_symbol);
+ const std::shared_ptr<type_info> info_object = std::make_shared<type_info>(parameter_symbol);
- info->position.emplace(parameter.position());
- info->file = this->module_file;
+ info_object->position.emplace(parameter.position());
+ info_object->file = this->module_file;
- if (this->bag.enter(parameter.name(), info))
+ if (this->bag.enter(parameter.name(), info_object))
{
result.push_back(parameter_symbol);
}
else
{
- auto original = this->bag.lookup(parameter.name());
+ const std::shared_ptr<info> original = this->bag.lookup(parameter.name());
add_error<symbol_declaration_error>(parameter.position(), parameter.name(),
symbol_declaration_error::redefinition{
@@ -556,7 +556,7 @@ namespace elna::boot
// to something other than a type is left to report.
if (this->current_type.empty())
{
- if (auto *named = expression.is_named();
+ if (const auto *named = expression.is_named();
named != nullptr && this->bag.lookup(named->name) != nullptr)
{
add_error<symbol_declaration_error>(named->position(),
@@ -639,13 +639,13 @@ namespace elna::boot
{
type base_type;
- if (auto unresolved_alias = this->bag.declared(expression->base.value().name()))
+ if (const auto unresolved_alias = this->bag.declared(expression->base.value().name()))
{
base_type = type(unresolved_alias);
}
- else if (auto base_symbol = this->bag.lookup(expression->base.value().name()))
+ else if (const auto base_symbol = this->bag.lookup(expression->base.value().name()))
{
- if (auto base_type_info = base_symbol->is_type())
+ if (const auto base_type_info = base_symbol->is_type())
{
base_type = base_type_info->symbol;
}
@@ -708,7 +708,7 @@ namespace elna::boot
for (const auto& member : expression->members)
{
- auto existing = seen.find(member.name());
+ const std::map<std::string, source_position>::const_iterator existing = seen.find(member.name());
if (existing != seen.end())
{
add_error<member_error>(member.position(), member.name(), aggregate,
@@ -799,13 +799,13 @@ namespace elna::boot
statement->body.symbols = this->bag.enter();
- auto label_symbol = std::make_shared<label_info>(this->defer_depth);
+ const std::shared_ptr<label_info> label_symbol = std::make_shared<label_info>(this->defer_depth);
label_symbol->position.emplace(statement->name.position());
label_symbol->file = this->module_file;
if (!this->bag.enter(label_name, label_symbol))
{
- auto original = this->bag.lookup(label_name);
+ const std::shared_ptr<info> original = this->bag.lookup(label_name);
symbol_declaration_error::redefinition original_definition{
.original = original->position,
.file = this->redefinition_file(original)
@@ -829,7 +829,7 @@ namespace elna::boot
symbol_declaration_error::kind::undeclared_label);
return;
}
- auto label_symbol = symbol->is_label();
+ const std::shared_ptr<label_info> label_symbol = symbol->is_label();
if (label_symbol == nullptr)
{
@@ -867,7 +867,7 @@ namespace elna::boot
void resolving_visitor::visit(procedure_call *call)
{
call->callable().accept(this);
- if (auto procedure = call->callable().type_decoration.get<procedure_type>())
+ if (const auto procedure = call->callable().type_decoration.get<procedure_type>())
{
call->type_decoration = procedure->return_type.proper_type;
}
@@ -888,9 +888,9 @@ namespace elna::boot
void resolving_visitor::visit(record_constructor_expression *expression)
{
- if (auto type_symbol = this->bag.lookup(expression->type_name.name()))
+ if (const auto type_symbol = this->bag.lookup(expression->type_name.name()))
{
- if (auto type_info = type_symbol->is_type())
+ if (const auto type_info = type_symbol->is_type())
{
expression->type_decoration = expression->arguments.empty()
? type_info->symbol
@@ -918,7 +918,7 @@ namespace elna::boot
void resolving_visitor::visit(array_constructor_expression *expression)
{
- for (auto *element : expression->elements)
+ for (auto *const element : expression->elements)
{
element->accept(this);
}
@@ -931,17 +931,17 @@ namespace elna::boot
void resolving_visitor::visit(slicing_expression *expression)
{
expression->base().accept(this);
- auto resolved_base = resolve_underlying_type(expression->base().type_decoration);
+ const type resolved_base = resolve_underlying_type(expression->base().type_decoration);
- if (auto pointer = resolved_base.get<pointer_type>())
+ if (const auto pointer = resolved_base.get<pointer_type>())
{
expression->type_decoration = type(std::make_shared<slice_type>(pointer->base));
}
- else if (auto array = resolved_base.get<array_type>())
+ else if (const auto array = resolved_base.get<array_type>())
{
expression->type_decoration = type(std::make_shared<slice_type>(array->base));
}
- else if (auto slice = resolved_base.get<slice_type>())
+ else if (const auto slice = resolved_base.get<slice_type>())
{
expression->type_decoration = type(slice);
}
@@ -1027,21 +1027,21 @@ namespace elna::boot
{
this->current_type = type();
- if (auto unresolved_alias = this->bag.declared(expression->name))
+ if (const 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))
+ else if (const auto from_symbol_table = this->bag.lookup(expression->name))
{
- if (auto type_symbol = from_symbol_table->is_type())
+ if (const auto type_symbol = from_symbol_table->is_type())
{
this->current_type = type_symbol->symbol;
}
- else if (auto variable_symbol = from_symbol_table->is_variable())
+ else if (const auto variable_symbol = from_symbol_table->is_variable())
{
expression->type_decoration = variable_symbol->symbol;
}
- else if (auto procedure_symbol = from_symbol_table->is_procedure())
+ else if (const auto procedure_symbol = from_symbol_table->is_procedure())
{
type procedure = type(std::make_shared<procedure_type>(procedure_symbol->symbol));
@@ -1051,7 +1051,7 @@ namespace elna::boot
procedure = substitute(procedure, procedure_symbol->parameters,
expression->argument_types);
}
- expression->type_decoration = procedure;
+ std::swap(expression->type_decoration, procedure);
return;
}
}
@@ -1092,11 +1092,11 @@ namespace elna::boot
{
expression->base().accept(this);
expression->index().accept(this);
- auto resolved_base = resolve_underlying_type(expression->base().type_decoration);
+ const type resolved_base = resolve_underlying_type(expression->base().type_decoration);
if (auto range_base = get_range_base_type(resolved_base))
{
- expression->type_decoration = range_base;
+ std::swap(expression->type_decoration, range_base);
// Elements of a constant array are constant themselves since a static
// array is a holistic type.
@@ -1113,11 +1113,11 @@ namespace elna::boot
// Handling field access on a type (only valid for enumerations).
if (!this->current_type.empty())
{
- auto resolved_base = resolve_underlying_type(this->current_type);
+ const type resolved_base = resolve_underlying_type(this->current_type);
- if (auto enumeration_base = resolved_base.get<enumeration_type>())
+ if (const auto enumeration_base = resolved_base.get<enumeration_type>())
{
- auto member_iterator = std::ranges::find(enumeration_base->members, expression->field().name());
+ const auto member_iterator = std::ranges::find(enumeration_base->members, expression->field().name());
if (member_iterator == enumeration_base->members.cend())
{
@@ -1158,7 +1158,7 @@ namespace elna::boot
{
expression->base().accept(this);
- if (auto pointer = resolve_underlying_type(expression->base().type_decoration).get<pointer_type>())
+ if (const auto pointer = resolve_underlying_type(expression->base().type_decoration).get<pointer_type>())
{
expression->type_decoration = pointer->base;
}
@@ -1251,7 +1251,7 @@ namespace elna::boot
* cycle is behind a pointer or a slice, so that the record layout
* stays finite. All other cycles are rejected.
*/
- if (auto link = referent.get<alias_type>())
+ if (const auto link = referent.get<alias_type>())
{
if (std::ranges::find(alias_path, link->name) != std::cend(alias_path))
{
@@ -1270,38 +1270,38 @@ namespace elna::boot
}
return acyclic;
}
- else if (auto link = referent.get<constant_type>())
+ else if (const auto link = referent.get<constant_type>())
{
return find_alias_cycle(being_resolved, link->unqualified, alias_path, state);
}
- else if (auto link = referent.get<pointer_type>())
+ else if (const auto link = referent.get<pointer_type>())
{
walk_state guarded_state = state;
guarded_state.guarded = true;
return find_alias_cycle(being_resolved, link->base, alias_path, guarded_state);
}
- else if (auto link = referent.get<slice_type>())
+ else if (const auto link = referent.get<slice_type>())
{
walk_state guarded_state = state;
guarded_state.guarded = true;
return find_alias_cycle(being_resolved, link->base, alias_path, guarded_state);
}
- else if (auto link = referent.get<array_type>())
+ else if (const auto link = referent.get<array_type>())
{
return find_alias_cycle(being_resolved, link->base, alias_path, state);
}
- else if (auto link = referent.get<generic_type>())
+ else if (const auto link = referent.get<generic_type>())
{
return find_alias_cycle(being_resolved, link->referent, alias_path, state);
}
- else if (auto link = referent.get<instantiated_type>())
+ else if (const auto link = referent.get<instantiated_type>())
{
// Erasure is argument blind, so the arguments cannot close a cycle
// the generic does not close on its own. This is what lets
// polymorphic recursion terminate.
return find_alias_cycle(being_resolved, link->generic, alias_path, state);
}
- else if (auto link = referent.get<procedure_type>())
+ else if (const auto link = referent.get<procedure_type>())
{
const std::size_t saved_path = alias_path.size();
@@ -1320,7 +1320,7 @@ namespace elna::boot
}
return true;
}
- else if (auto link = referent.get<record_type>())
+ else if (const auto link = referent.get<record_type>())
{
const std::size_t saved_path = alias_path.size();
walk_state in_record = state;
@@ -1353,7 +1353,7 @@ namespace elna::boot
}
if (unit->entry_point.has_value())
{
- auto word8_primitive = lookup_primitive_type("Word8");
+ const type 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<procedure_info> info;
@@ -1385,8 +1385,6 @@ namespace elna::boot
info->position = unit->entry_position;
info->file = this->module_file;
- // A unit has at most one entry point and an imported program is
- // rejected before its symbols are merged, so this cannot collide.
this->bag.enter("", info);
}
}
@@ -1411,23 +1409,22 @@ namespace elna::boot
// Reject the cycle and wire an empty referent: the declaration still
// resolves and is entered, so its uses degrade silently.
- if (auto cycle = find_alias_cycle(
- this->bag.declared(declaration->identifier.name()), underlying))
+ if (const auto cycle = find_alias_cycle(this->bag.declared(declaration->identifier.name()), underlying))
{
add_error<cyclic_declaration_error>(declaration->position(), *cycle);
underlying = type();
}
const std::shared_ptr<alias_type> resolved =
this->bag.resolve(declaration->identifier.name(), underlying);
- auto info = std::make_shared<type_info>(type(resolved));
+ const std::shared_ptr<type_info> info_object = std::make_shared<type_info>(type(resolved));
- info->exported = declaration->identifier.exported();
- info->position.emplace(declaration->position());
- info->file = this->module_file;
+ info_object->exported = declaration->identifier.exported();
+ info_object->position.emplace(declaration->position());
+ info_object->file = this->module_file;
- if (!this->bag.enter(declaration->identifier.name(), info))
+ if (!this->bag.enter(declaration->identifier.name(), info_object))
{
- auto original = this->bag.lookup(declaration->identifier.name());
+ const std::shared_ptr<info> original = this->bag.lookup(declaration->identifier.name());
symbol_declaration_error::redefinition original_definition{
.original = original->position,
.file = this->redefinition_file(original)
@@ -1455,7 +1452,7 @@ namespace elna::boot
}
else if (!declaration->is_extern && resolve_aliases(variable_type).get<constant_type>() != nullptr)
{
- auto position_span = source_position(
+ 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,
@@ -1463,7 +1460,7 @@ namespace elna::boot
}
for (const auto& variable_identifier : declaration->identifiers)
{
- auto variable_symbol = register_variable(variable_identifier.name(),
+ const std::shared_ptr<variable_info> variable_symbol = register_variable(variable_identifier.name(),
variable_type, declaration->position(), declaration->is_extern);
variable_symbol->exported = variable_identifier.exported();
variable_symbol->alignment =
@@ -1482,18 +1479,19 @@ namespace elna::boot
const std::vector<type> type_parameters = enter_parameters(declaration->parameters);
auto [heading, parameter_names] =
build_procedure(declaration->heading(), !declaration->body.has_value());
- std::shared_ptr<procedure_info> info;
+ std::shared_ptr<procedure_info> info_object;
if (declaration->body.has_value())
{
- info = std::make_shared<procedure_info>(heading, std::move(parameter_names), scope);
- auto name_iterator = std::cbegin(info->names);
- auto type_iterator = std::cbegin(info->symbol.parameters);
+ info_object = std::make_shared<procedure_info>(heading, std::move(parameter_names), scope);
+ auto name_iterator = std::cbegin(info_object->names);
+ auto type_iterator = std::cbegin(info_object->symbol.parameters);
- while (name_iterator != std::cend(info->names) && type_iterator != std::cend(info->symbol.parameters))
+ while (name_iterator != std::cend(info_object->names)
+ && type_iterator != std::cend(info_object->symbol.parameters))
{
- auto variable_symbol = register_variable(*name_iterator, *type_iterator,
- declaration->heading().position());
+ const std::shared_ptr<variable_info> variable_symbol =
+ register_variable(*name_iterator, *type_iterator, declaration->heading().position());
++name_iterator;
++type_iterator;
@@ -1501,16 +1499,16 @@ namespace elna::boot
}
else
{
- info = std::make_shared<procedure_info>(heading, std::move(parameter_names));
+ info_object = std::make_shared<procedure_info>(heading, std::move(parameter_names));
}
this->bag.leave();
- info->parameters = type_parameters;
- info->exported = declaration->identifier.exported();
- info->position.emplace(declaration->position());
- info->file = this->module_file;
- if (!this->bag.enter(declaration->identifier.name(), info))
+ info_object->parameters = type_parameters;
+ info_object->exported = declaration->identifier.exported();
+ info_object->position.emplace(declaration->position());
+ info_object->file = this->module_file;
+ if (!this->bag.enter(declaration->identifier.name(), info_object))
{
- auto original = this->bag.lookup(declaration->identifier.name());
+ const std::shared_ptr<info> original = this->bag.lookup(declaration->identifier.name());
symbol_declaration_error::redefinition original_definition{
.original = original->position,
.file = this->redefinition_file(original)
@@ -1541,9 +1539,11 @@ namespace elna::boot
{
const std::shared_ptr<procedure_info> info = this->bag.lookup("")->is_procedure();
- unit->entry_point->symbols = info->scope;
this->bag.enter(info->scope);
- traverse_body(this, unit->entry_point.value());
+ for (statement *body_statement : unit->entry_point.value())
+ {
+ body_statement->accept(this);
+ }
this->bag.leave();
}
}
@@ -1564,7 +1564,7 @@ namespace elna::boot
}
else if (resolve_aliases(variable_type).get<constant_type>() != nullptr)
{
- auto position_span = source_position(
+ 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,
@@ -1572,7 +1572,7 @@ namespace elna::boot
}
for (const auto& variable_identifier : declaration->identifiers)
{
- auto variable_symbol = register_variable(variable_identifier.name(),
+ const std::shared_ptr<variable_info> variable_symbol = register_variable(variable_identifier.name(),
variable_type, declaration->position(), declaration->is_extern);
variable_symbol->exported = variable_identifier.exported();
variable_symbol->alignment =
@@ -1598,7 +1598,7 @@ namespace elna::boot
void name_analysis_visitor::visit(for_statement *statement)
{
statement->range().accept(this);
- auto resolved_range = resolve_underlying_type(statement->range().type_decoration);
+ const type 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<pointer_type>(control_variable_base_type));
const type control_variable_const_type = type(std::make_shared<constant_type>(control_variable_pointer_type));
diff --git a/boot/parser.yy b/boot/parser.yy
index 01dfa80..1e732c6 100644
--- a/boot/parser.yy
+++ b/boot/parser.yy
@@ -95,12 +95,11 @@ along with GCC; see the file COPYING3. If not see
EXCLAMATION "!" ARROW "->"
AT "@" HAT "^"
COLON ":" SEMICOLON ";" DOT "." COMMA ","
-%token PROGRAM "program"
+%token PROGRAM "program" MODULE "module"
CAST "cast"
NIL "nil"
CONST "const"
- VAR "var"
- THREADVAR "threadvar"
+ VAR "var" THREADVAR "threadvar"
PROCEDURE "proc"
TYPE "type"
RECORD "record"
@@ -135,7 +134,7 @@ along with GCC; see the file COPYING3. If not see
%type <elna::boot::switch_case> switch_case;
%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 variable_part;
+%type <std::vector<elna::boot::variable_declaration *>> variable_declarations;
%type <elna::boot::type_expression *> type_expression;
%type <std::vector<elna::boot::type_expression *>> type_expressions;
%type <elna::boot::expression *> expression operand simple_expression procedure_return unary_expression;
@@ -144,14 +143,15 @@ along with GCC; see the file COPYING3. If not see
%type <elna::boot::designator_expression *> designator_expression;
%type <std::unique_ptr<elna::boot::procedure_call>> call_expression;
%type <elna::boot::statement *> statement;
-%type <std::vector<elna::boot::statement *>> statements statement_part;
+%type <std::vector<elna::boot::statement *>> statements statement_part optional_begin_statements;
%type <elna::boot::block> block;
%type <elna::boot::procedure_declaration *> procedure_declaration;
%type <std::unique_ptr<elna::boot::procedure_type_expression>> procedure_heading;
%type <elna::boot::procedure_type_expression::return_t> return_declaration;
%type <std::unique_ptr<elna::boot::type_declaration>> type_declaration;
-%type <std::vector<elna::boot::declaration *>> type_declarations;
-%type <std::vector<elna::boot::declaration *>> module_declaration module_declarations;
+%type <std::vector<elna::boot::declaration *>> type_declarations sections section;
+%type <std::pair<std::vector<elna::boot::import_declaration *>, std::vector<elna::boot::declaration *>>>
+ required_declarations optional_declarations;
%type <std::unique_ptr<elna::boot::procedure_body>> procedure_body;
%type <elna::boot::field_declaration> field_declaration;
%type <std::vector<elna::boot::field_declaration>> field_declarations;
@@ -167,31 +167,38 @@ along with GCC; see the file COPYING3. If not see
%type <std::vector<std::string>> import_declaration;
%type <std::vector<elna::boot::identifier>> required_identifiers optional_identifiers generic_parameters;
%type <elna::boot::named_expression *> name_reference;
-%type <std::vector<elna::boot::import_declaration *>> import_declarations import_part;
+%type <std::vector<elna::boot::import_declaration *>> import_declarations;
%type <std::unique_ptr<elna::boot::array_type_expression>> array_type_expression;
+%type <std::unique_ptr<elna::boot::unit>> unit;
%%
-program:
- import_part module_declarations "end" "."
+program: unit
{
- driver.finished = true;
+ driver.tree = $1;
+ }
+unit:
+ "module" optional_declarations "end" "."
+ {
+ auto [modules, sections] = $2;
- boot::unit *tree = new boot::unit(boot::make_position(@$), $1, $2);
- driver.tree.reset(tree);
+ $$ = std::make_unique<boot::unit>(boot::make_position(@$), std::move(modules), std::move(sections));
}
- | import_part module_declarations
- "program" "(" optional_identifiers ")" procedure_body "end" "."
+ | "program" "(" optional_identifiers ")" required_declarations statement_part "end" "."
{
- driver.finished = true;
+ auto [modules, sections] = $5;
- boot::unit *tree = new boot::unit(boot::make_position(@$), $1, $2,
- std::move($5), boot::make_position(@3), std::move(*$7));
- driver.tree.reset(tree);
+ $$ = std::make_unique<boot::unit>(boot::make_position(@$), std::move(modules),
+ std::move(sections), $3, boot::make_position(@1), $6);
}
-module_declaration:
+ | "program" "(" optional_identifiers ")" optional_begin_statements "end" "."
+ {
+ $$ = std::make_unique<boot::unit>(boot::make_position(@$), std::vector<boot::import_declaration *>{},
+ std::vector<boot::declaration *>{}, $3, boot::make_position(@1), $5);
+ }
+section:
"type" type_declarations { $$ = $2; }
- | variable_part
+ | "var" variable_declarations
{
- std::vector<boot::variable_declaration *> variables = $1;
+ std::vector<boot::variable_declaration *> variables = $2;
$$.insert($$.end(), variables.begin(), variables.end());
}
@@ -206,33 +213,36 @@ module_declaration:
$$.insert($$.end(), variables.begin(), variables.end());
}
| procedure_declaration { $$.emplace_back($1); }
-module_declarations:
+required_declarations:
+ sections { $$ = { {}, $1 }; }
+ | "import" import_declarations { $$ = { $2, {} }; }
+ | "import" import_declarations sections { $$ = { $2, $3 }; }
+optional_declarations:
%empty {}
- | module_declaration module_declarations
+ | required_declarations { $$ = $1; }
+sections:
+ section sections
{
std::vector<boot::declaration *> appendix = $2;
$$ = $1;
$$.insert($$.end(), appendix.begin(), appendix.end());
}
+ | section { $$ = $1; }
procedure_body:
block procedure_return
{ $$ = std::make_unique<boot::procedure_body>(std::move($1), $2); }
-
-variable_part:
- "var" variable_declarations { $$ = $2; }
-
block:
- variable_part statement_part
- { $$ = boot::block(std::move($1), std::move($2)); }
- | "begin" statements
- { $$ = boot::block(std::vector<boot::variable_declaration *>(), std::move($2)); }
- | statements
+ "var" variable_declarations statement_part
+ { $$ = boot::block(std::move($2), std::move($3)); }
+ | optional_begin_statements
{ $$ = boot::block(std::vector<boot::variable_declaration *>(), std::move($1)); }
-
statement_part:
%empty {}
| "begin" statements { $$ = $2; }
+optional_begin_statements:
+ "begin" statements { $$ = $2; }
+ | statements { $$ = $1; }
identifier:
IDENTIFIER { $$ = std::make_unique<boot::identifier>($1, boot::make_position(@1)); }
identifier_definition:
@@ -739,9 +749,6 @@ import_declarations:
{
$$.emplace_back(new boot::import_declaration(boot::make_position(@$), $1));
}
-import_part:
- %empty {}
- | "import" import_declarations { $$ = $2; }
type_declaration: identifier_definition generic_parameters "=" type_expression
{
$$ = std::make_unique<boot::type_declaration>(boot::make_position(@$), std::move(*$1), $4);
diff --git a/boot/result.cc b/boot/result.cc
index c8ea267..71326c0 100644
--- a/boot/result.cc
+++ b/boot/result.cc
@@ -131,7 +131,7 @@ namespace elna::boot
std::optional<diagnostic_note> identifier_list_note(
const std::vector<identifier>& identifiers)
{
- auto position_span = source_position(identifiers.front().position().start(),
+ const source_position position_span = source_position(identifiers.front().position().start(),
identifiers.back().position().end());
return diagnostic_note{ .message = join(identifiers), .position = position_span, .file = {} };
@@ -501,7 +501,7 @@ namespace elna::boot
constexpr std::size_t shortest_round_trip = 24;
std::array<char, shortest_round_trip + 4> buffer;
- auto float_chars = std::to_chars(buffer.begin(), buffer.end(), this->raw);
+ const std::to_chars_result float_chars = std::to_chars(buffer.begin(), buffer.end(), this->raw);
return std::string(buffer.begin(), float_chars.ptr);
}
@@ -557,7 +557,8 @@ std::size_t std::hash<elna::boot::constant_aggregate<std::vector>>::operator()(
const elna::boot::constant_aggregate<std::vector>& key) const noexcept
{
const elna::boot::constant_value_hash hasher{};
- auto hash = std::accumulate(key->begin(), key->end(), elna::boot::hash_accumulator{},
+ const elna::boot::hash_accumulator hash = std::accumulate(key->begin(), key->end(),
+ elna::boot::hash_accumulator{},
[&hasher](const auto& accumulator, const auto& element) {
return accumulator + hasher(element);
});
@@ -569,7 +570,8 @@ std::size_t std::hash<elna::boot::constant_aggregate<elna::boot::ordered_map>>::
const elna::boot::constant_aggregate<elna::boot::ordered_map>& key) const noexcept
{
const elna::boot::constant_value_hash hasher{};
- auto hash = std::accumulate(key->begin(), key->end(), elna::boot::hash_accumulator{},
+ const elna::boot::hash_accumulator hash = std::accumulate(key->begin(), key->end(),
+ elna::boot::hash_accumulator{},
[&hasher](const auto& accumulator, const auto& element) {
return accumulator + std::hash<std::string>{}(element.first) + hasher(element.second);
});
diff --git a/boot/symbol.cc b/boot/symbol.cc
index 962808a..54cb595 100644
--- a/boot/symbol.cc
+++ b/boot/symbol.cc
@@ -67,77 +67,80 @@ namespace elna::boot
bool type::operator==(const type& other) const
{
- type const resolved_this = resolve_aliases(*this);
- type const resolved_that = resolve_aliases(other);
+ const type resolved_this = resolve_aliases(*this);
+ const type resolved_that = resolve_aliases(other);
- if (auto left_record = resolved_this.get<record_type>())
+ if (const auto left_record = resolved_this.get<record_type>())
{
return left_record == resolved_that.get<record_type>();
}
- if (auto left_primitive = resolved_this.get<primitive_type>())
+ else if (const auto left_primitive = resolved_this.get<primitive_type>())
{
- auto right_primitive = resolved_that.get<primitive_type>();
+ const std::shared_ptr<primitive_type> right_primitive = resolved_that.get<primitive_type>();
return right_primitive != nullptr && left_primitive->identifier == right_primitive->identifier;
}
- if (auto left_enumeration = resolved_this.get<enumeration_type>())
+ else if (const auto left_enumeration = resolved_this.get<enumeration_type>())
{
return left_enumeration == resolved_that.get<enumeration_type>();
}
- if (auto left_extern = resolved_this.get<extern_type>())
+ else if (const auto left_extern = resolved_this.get<extern_type>())
{
return left_extern == resolved_that.get<extern_type>();
}
- if (auto left_pointer = resolved_this.get<pointer_type>())
+ else if (const auto left_pointer = resolved_this.get<pointer_type>())
{
- auto right_pointer = resolved_that.get<pointer_type>();
+ const std::shared_ptr<pointer_type> right_pointer = resolved_that.get<pointer_type>();
return right_pointer != nullptr && left_pointer->base == right_pointer->base;
}
- if (auto left_const = resolved_this.get<constant_type>())
+ else if (const auto left_const = resolved_this.get<constant_type>())
{
- auto right_const = resolved_that.get<constant_type>();
+ const std::shared_ptr<constant_type> right_const = resolved_that.get<constant_type>();
return right_const != nullptr && left_const->unqualified == right_const->unqualified;
}
- if (auto left_array = resolved_this.get<array_type>())
+ else if (const auto left_array = resolved_this.get<array_type>())
{
- auto right_array = resolved_that.get<array_type>();
+ const std::shared_ptr<array_type> right_array = resolved_that.get<array_type>();
return right_array != nullptr && left_array->size == right_array->size
&& left_array->base == right_array->base;
}
- if (auto left_slice = resolved_this.get<slice_type>())
+ else if (const auto left_slice = resolved_this.get<slice_type>())
{
- auto right_slice = resolved_that.get<slice_type>();
+ const std::shared_ptr<slice_type> right_slice = resolved_that.get<slice_type>();
return right_slice != nullptr && left_slice->base == right_slice->base;
}
- if (auto left_procedure = resolved_this.get<procedure_type>())
+ else if (const auto left_procedure = resolved_this.get<procedure_type>())
{
- auto right_procedure = resolved_that.get<procedure_type>();
+ const std::shared_ptr<procedure_type> right_procedure = resolved_that.get<procedure_type>();
return right_procedure != nullptr && left_procedure->return_type == right_procedure->return_type
&& left_procedure->parameters == right_procedure->parameters
&& left_procedure->variadic == right_procedure->variadic;
}
- if (auto left_parameter = resolved_this.get<parameter_type>())
+ else if (const auto left_parameter = resolved_this.get<parameter_type>())
{
return left_parameter == resolved_that.get<parameter_type>();
}
- if (auto left_generic = resolved_this.get<generic_type>())
+ else if (const auto left_generic = resolved_this.get<generic_type>())
{
return left_generic == resolved_that.get<generic_type>();
}
- if (auto left_instance = resolved_this.get<instantiated_type>())
+ else if (const auto left_instance = resolved_this.get<instantiated_type>())
{
- auto right_instance = resolved_that.get<instantiated_type>();
+ const std::shared_ptr<instantiated_type> right_instance = resolved_that.get<instantiated_type>();
return right_instance != nullptr
&& left_instance->generic == right_instance->generic
&& left_instance->arguments == right_instance->arguments;
}
- return resolved_this.empty() && resolved_that.empty();
+ else
+ {
+ return resolved_this.empty() && resolved_that.empty();
+ }
}
type::operator bool() const
@@ -378,14 +381,14 @@ namespace elna::boot
// matching the machine word.
if (bit_size == properties.front().size * CHAR_BIT)
{
- auto alias = std::make_shared<alias_type>(integer_name, variant_type);
+ const std::shared_ptr<alias_type> alias = std::make_shared<alias_type>(integer_name, variant_type);
symbols->enter(integer_name, std::make_shared<type_info>(type(alias)));
}
}
if (!symbols->contains(integer_name))
{
- auto variant_type = type(std::make_shared<primitive_type>(integer_name, properties.front()));
+ const type variant_type = type(std::make_shared<primitive_type>(integer_name, properties.front()));
symbols->enter(integer_name, std::make_shared<type_info>(variant_type));
}
@@ -489,14 +492,14 @@ namespace elna::boot
std::shared_ptr<alias_type> symbol_bag::declared(const std::string& symbol_name)
{
- auto unresolved_alias = this->unresolved.find(symbol_name);
+ const auto unresolved_alias = this->unresolved.find(symbol_name);
return unresolved_alias == this->unresolved.end() ? std::shared_ptr<alias_type>() : unresolved_alias->second;
}
std::shared_ptr<alias_type> symbol_bag::resolve(const std::string& symbol_name, type& resolution)
{
- auto unresolved_node = this->unresolved.extract(symbol_name);
+ const auto unresolved_node = this->unresolved.extract(symbol_name);
assert(!unresolved_node.empty());
auto unresolved_declaration = unresolved_node.mapped();
@@ -563,7 +566,7 @@ namespace elna::boot
{
type resolved_alias = resolve_aliases(alias);
- if (auto qualified = resolved_alias.get<constant_type>())
+ if (const auto qualified = resolved_alias.get<constant_type>())
{
return resolve_underlying_type(qualified->unqualified);
}
@@ -575,7 +578,7 @@ namespace elna::boot
type unwrap_aliases(const type& checked)
{
- if (auto alias = checked.get<alias_type>())
+ if (const auto alias = checked.get<alias_type>())
{
return unwrap_aliases(alias->referent);
}
@@ -590,7 +593,7 @@ namespace elna::boot
type substitute(const type& subject, const std::vector<type>& parameters,
const std::vector<type>& arguments)
{
- if (auto parameter = subject.get<parameter_type>())
+ if (const auto parameter = subject.get<parameter_type>())
{
for (std::size_t i = 0; i < parameters.size() && i < arguments.size(); ++i)
{
@@ -601,27 +604,27 @@ namespace elna::boot
}
return subject;
}
- if (auto pointer = subject.get<pointer_type>())
+ else if (const auto pointer = subject.get<pointer_type>())
{
return type(std::make_shared<pointer_type>(
substitute(pointer->base, parameters, arguments)));
}
- if (auto slice = subject.get<slice_type>())
+ else if (const auto slice = subject.get<slice_type>())
{
return type(std::make_shared<slice_type>(
substitute(slice->base, parameters, arguments)));
}
- if (auto array = subject.get<array_type>())
+ else if (const auto array = subject.get<array_type>())
{
return type(std::make_shared<array_type>(
substitute(array->base, parameters, arguments), array->size));
}
- if (auto qualified = subject.get<constant_type>())
+ else if (const auto qualified = subject.get<constant_type>())
{
return type(std::make_shared<constant_type>(
substitute(qualified->unqualified, parameters, arguments)));
}
- if (auto procedure = subject.get<procedure_type>())
+ else if (const auto procedure = subject.get<procedure_type>())
{
procedure_type::return_t result_return = procedure->return_type;
@@ -630,7 +633,7 @@ namespace elna::boot
result_return = procedure_type::return_t(
substitute(result_return.proper_type, parameters, arguments));
}
- auto result = std::make_shared<procedure_type>(std::move(result_return));
+ const std::shared_ptr<procedure_type> result = std::make_shared<procedure_type>(std::move(result_return));
result->variadic = procedure->variadic;
result->parameters.reserve(procedure->parameters.size());
@@ -640,7 +643,7 @@ namespace elna::boot
}
return type(result);
}
- if (auto instance = subject.get<instantiated_type>())
+ else if (const auto instance = subject.get<instantiated_type>())
{
std::vector<type> substituted;
@@ -667,17 +670,20 @@ namespace elna::boot
{
type resolved = resolve_underlying_type(checked);
- if (auto instance = resolved.get<instantiated_type>())
+ if (const auto instance = resolved.get<instantiated_type>())
{
std::shared_ptr<generic_type> const generic = unwrap_generic(instance->generic);
return generic == nullptr ? type() : resolve_underlying_type(generic->referent);
}
- if (auto generic = resolved.get<generic_type>())
+ else if (const auto generic = resolved.get<generic_type>())
{
return resolve_underlying_type(generic->referent);
}
- return resolved;
+ else
+ {
+ return resolved;
+ }
}
/*
@@ -686,13 +692,13 @@ namespace elna::boot
*/
static type substitute_from(const type& subject, const type& taken)
{
- auto instance = subject.get<instantiated_type>();
+ const std::shared_ptr<instantiated_type> instance = subject.get<instantiated_type>();
if (instance == nullptr)
{
return taken;
}
- std::shared_ptr<generic_type> const generic = unwrap_generic(instance->generic);
+ const std::shared_ptr<generic_type> generic = unwrap_generic(instance->generic);
return generic == nullptr
? type()
@@ -702,7 +708,7 @@ namespace elna::boot
type base_of(const type& derived)
{
const type resolved = resolve_underlying_type(derived);
- auto record = erase_generic(resolved).get<record_type>();
+ const std::shared_ptr<record_type> record = erase_generic(resolved).get<record_type>();
return record == nullptr || record->base.empty()
? type()
@@ -723,13 +729,13 @@ namespace elna::boot
type resolve_aliases(const type& checked)
{
- if (auto alias = checked.get<alias_type>())
+ if (const auto alias = checked.get<alias_type>())
{
return resolve_aliases(alias->referent);
}
- if (auto instance = checked.get<instantiated_type>())
+ else if (const auto instance = checked.get<instantiated_type>())
{
- std::shared_ptr<generic_type> const generic = unwrap_generic(instance->generic);
+ const std::shared_ptr<generic_type> generic = unwrap_generic(instance->generic);
// A record referent makes the instantiation nominal, so resolution
// stops here and Stack#[^File] stays distinct from Stack#[^Socket].
@@ -744,7 +750,7 @@ namespace elna::boot
bool is_primitive_type(const type& checked, const std::string& name)
{
- if (auto primitive_checked = checked.get<primitive_type>())
+ if (const auto primitive_checked = checked.get<primitive_type>())
{
return primitive_checked->identifier == name;
}
@@ -753,7 +759,7 @@ namespace elna::boot
bool is_integer_type(const type& checked)
{
- if (auto primitive_checked = checked.get<primitive_type>())
+ if (const auto primitive_checked = checked.get<primitive_type>())
{
return primitive_checked->identifier.starts_with("Int");
}
@@ -762,7 +768,7 @@ namespace elna::boot
bool is_word_type(const type& checked)
{
- if (auto primitive_checked = checked.get<primitive_type>())
+ if (const auto primitive_checked = checked.get<primitive_type>())
{
return primitive_checked->identifier.starts_with("Word");
}
@@ -811,9 +817,9 @@ namespace elna::boot
bool is_string_type(const type& checked)
{
- if (auto slice = checked.get<slice_type>())
+ if (const auto slice = checked.get<slice_type>())
{
- if (auto base = resolve_aliases(slice->base).get<constant_type>())
+ if (const auto base = resolve_aliases(slice->base).get<constant_type>())
{
return is_primitive_type(resolve_aliases(base->unqualified), "Word8");
}
@@ -823,11 +829,11 @@ namespace elna::boot
type get_range_base_type(const type& range)
{
- if (auto array = range.get<array_type>())
+ if (const auto array = range.get<array_type>())
{
return array->base;
}
- else if (auto slice = range.get<slice_type>())
+ else if (const auto slice = range.get<slice_type>())
{
return slice->base;
}
@@ -838,7 +844,7 @@ namespace elna::boot
{
const type resolved_type = resolve_underlying_type(composite_type);
- if (auto record = erase_generic(resolved_type).get<record_type>())
+ if (const auto record = erase_generic(resolved_type).get<record_type>())
{
for (const auto& [name, field] : record->fields)
{
diff --git a/boot/type_check.cc b/boot/type_check.cc
index 5d5bc59..7be236d 100644
--- a/boot/type_check.cc
+++ b/boot/type_check.cc
@@ -44,7 +44,7 @@ namespace elna::boot
__builtin_unreachable();
}
- static std::string print_binary_operator(const binary_operator operation)
+ static std::string_view print_binary_operator(const binary_operator operation)
{
switch (operation)
{
@@ -215,7 +215,7 @@ namespace elna::boot
{
return "Invalid operands of type '" + this->actual.to_string()
+ "' and '" + payload.right.to_string()
- + "' for operator " + print_binary_operator(payload.operation);
+ + "' for operator " + std::string(print_binary_operator(payload.operation));
}
else if constexpr (std::is_same_v<T, invalid_cast>)
{
@@ -345,13 +345,13 @@ namespace elna::boot
static bool contains_constant_member(const type& checked)
{
- auto referent = resolve_aliases(checked);
+ const type referent = resolve_aliases(checked);
if (referent.get<constant_type>() != nullptr)
{
return true;
}
- else if (auto record = referent.get<record_type>())
+ else if (const auto record = referent.get<record_type>())
{
for (const auto& [field_name, field] : record->fields)
{
@@ -363,7 +363,7 @@ namespace elna::boot
return !record->base.empty()
&& contains_constant_member(resolve_underlying_type(record->base));
}
- else if (auto array = referent.get<array_type>())
+ else if (const auto array = referent.get<array_type>())
{
return contains_constant_member(array->base);
}
@@ -385,30 +385,30 @@ namespace elna::boot
}
const type referent = resolve_aliases(checked);
- if (auto record = referent.get<record_type>())
+ if (const auto record = referent.get<record_type>())
{
for (const auto& [field_name, field] : record->fields)
{
- if (auto opaque = find_opaque_type(field.field_type))
+ if (const auto opaque = find_opaque_type(field.field_type))
{
return opaque;
}
}
return !record->base.empty() ? find_opaque_type(record->base) : std::nullopt;
}
- else if (auto array = referent.get<array_type>())
+ else if (const auto array = referent.get<array_type>())
{
return find_opaque_type(array->base);
}
- else if (auto slice = referent.get<slice_type>())
+ else if (const auto slice = referent.get<slice_type>())
{
return find_opaque_type(slice->base);
}
- else if (auto procedure = referent.get<procedure_type>())
+ else if (const auto procedure = referent.get<procedure_type>())
{
for (const type& parameter : procedure->parameters)
{
- if (auto opaque = find_opaque_type(parameter))
+ if (const auto opaque = find_opaque_type(parameter))
{
return opaque;
}
@@ -446,7 +446,7 @@ namespace elna::boot
{
return std::nullopt;
}
- if (auto pointer = (lhs_integral ? rhs : lhs).get<pointer_type>())
+ if (const auto pointer = (lhs_integral ? rhs : lhs).get<pointer_type>())
{
return find_opaque_type(pointer->base);
}
@@ -456,7 +456,8 @@ namespace elna::boot
// Checks whether the type has zero size.
static bool has_zero_size(const type& checked, const target_info& target)
{
- auto properties = get_type_properties(resolve_underlying_type(checked), target);
+ const std::optional<type_properties> properties =
+ get_type_properties(resolve_underlying_type(checked), target);
return properties.has_value() && properties->size == 0;
}
@@ -469,7 +470,7 @@ namespace elna::boot
{
return checked;
}
- if (auto record = resolve_aliases(checked).get<record_type>())
+ if (const auto record = resolve_aliases(checked).get<record_type>())
{
for (const auto& [field_name, field] : record->fields)
{
@@ -520,23 +521,18 @@ namespace elna::boot
}
}
- /*
- * Checks whether derived has base in its record parent chain.
- *
- * Base record type must not be null. Derived record type may be null.
- */
assign_check::verdict assign_check::guard_const_laundering() const
{
if (!is_primitive_type(ctx.aliased_assignee, "Pointer"))
{
return verdict::pass;
}
- if (auto ptr = ctx.aliased_assignment.get<pointer_type>();
+ if (const auto ptr = ctx.aliased_assignment.get<pointer_type>();
ptr != nullptr && resolve_aliases(ptr->base).get<constant_type>() != nullptr)
{
return verdict::reject;
}
- if (auto const_assign = ctx.aliased_assignment.get<constant_type>();
+ if (const auto const_assign = ctx.aliased_assignment.get<constant_type>();
const_assign != nullptr && is_primitive_type(const_assign->unqualified, "Pointer"))
{
return verdict::reject;
@@ -566,15 +562,16 @@ namespace elna::boot
assign_check::verdict assign_check::check_pointer_conversion() const
{
- auto assignee_ptr = ctx.resolved_assignee.get<pointer_type>();
- auto assignment_ptr = ctx.resolved_assignment.get<pointer_type>();
+ const std::shared_ptr<pointer_type> assignee_ptr = ctx.resolved_assignee.get<pointer_type>();
+ const std::shared_ptr<pointer_type> assignment_ptr = ctx.resolved_assignment.get<pointer_type>();
if (assignee_ptr == nullptr || assignment_ptr == nullptr)
{
return verdict::pass;
}
- auto assignee_pointee_const = resolve_aliases(assignee_ptr->base).get<constant_type>();
- auto assignment_pointee_const = resolve_aliases(assignment_ptr->base).get<constant_type>();
+ const std::shared_ptr<constant_type> assignee_pointee_const =
+ resolve_aliases(assignee_ptr->base).get<constant_type>();
+ const std::shared_ptr<constant_type> assignment_pointee_const = resolve_aliases(assignment_ptr->base).get<constant_type>();
// Constness can be added at the first indirection level, but not removed.
if (assignee_pointee_const != nullptr
@@ -599,15 +596,17 @@ namespace elna::boot
assign_check::verdict assign_check::check_slice_conversion() const
{
- auto assignee_slice = ctx.resolved_assignee.get<slice_type>();
- auto assignment_slice = ctx.resolved_assignment.get<slice_type>();
+ const std::shared_ptr<slice_type> assignee_slice = ctx.resolved_assignee.get<slice_type>();
+ const std::shared_ptr<slice_type> assignment_slice = ctx.resolved_assignment.get<slice_type>();
if (assignee_slice == nullptr || assignment_slice == nullptr)
{
return verdict::pass;
}
- auto assignee_element_const = resolve_aliases(assignee_slice->base).get<constant_type>();
- auto assignment_element_const = resolve_aliases(assignment_slice->base).get<constant_type>();
+ const std::shared_ptr<constant_type> assignee_element_const =
+ resolve_aliases(assignee_slice->base).get<constant_type>();
+ const std::shared_ptr<constant_type> assignment_element_const =
+ resolve_aliases(assignment_slice->base).get<constant_type>();
// Const can be added to the element type, but not removed.
if (assignee_element_const != nullptr
@@ -624,16 +623,18 @@ namespace elna::boot
assign_check::verdict assign_check::check_array_conversion() const
{
- auto assignee_array = ctx.resolved_assignee.get<array_type>();
- auto assignment_array = ctx.resolved_assignment.get<array_type>();
+ const std::shared_ptr<array_type> assignee_array = ctx.resolved_assignee.get<array_type>();
+ const std::shared_ptr<array_type> assignment_array = ctx.resolved_assignment.get<array_type>();
if (assignee_array == nullptr || assignment_array == nullptr
|| assignee_array->size != assignment_array->size)
{
return verdict::pass;
}
- auto assignee_element_const = resolve_aliases(assignee_array->base).get<constant_type>();
- auto assignment_element_const = resolve_aliases(assignment_array->base).get<constant_type>();
+ const std::shared_ptr<constant_type> assignee_element_const =
+ resolve_aliases(assignee_array->base).get<constant_type>();
+ const std::shared_ptr<constant_type> assignment_element_const =
+ resolve_aliases(assignment_array->base).get<constant_type>();
// An array is copied by value, so const can be added to the element type,
// but not removed. Writing to such an array is rejected on the lvalue.
@@ -651,7 +652,7 @@ namespace elna::boot
bool assign_check::run()
{
- auto const assign_handlers = {
+ const std::initializer_list assign_handlers = {
&assign_check::guard_const_laundering,
&assign_check::check_exact_match,
&assign_check::check_slice_conversion,
@@ -659,7 +660,7 @@ namespace elna::boot
&assign_check::check_pointer_hatch,
&assign_check::check_pointer_conversion
};
- for (auto handler : assign_handlers)
+ for (const auto handler : assign_handlers)
{
switch ((this->*handler)())
{
@@ -804,7 +805,6 @@ namespace elna::boot
this->current_procedure = this->bag.lookup("")->is_procedure();
this->bag.enter(this->current_procedure->scope);
walking_visitor::visit_entry_point(unit);
- check_return(unit->entry_point.value(), unit->entry_position.value(), "");
this->bag.leave();
this->current_procedure.reset();
}
@@ -815,14 +815,15 @@ namespace elna::boot
for (const auto& variable_identifier : declaration->identifiers)
{
- auto variable_symbol = this->bag.lookup(variable_identifier.name())->is_variable();
+ const std::shared_ptr<variable_info> variable_symbol =
+ this->bag.lookup(variable_identifier.name())->is_variable();
- if (auto opaque = find_opaque_type(variable_symbol->symbol))
+ if (const auto opaque = find_opaque_type(variable_symbol->symbol))
{
add_error<type_requirement_error>(variable_identifier.id().position(),
opaque.value(), type_requirement_error::kind::opaque_variable);
}
- else if (auto found = find_zero_sized(variable_symbol->symbol, this->target))
+ else if (const auto found = find_zero_sized(variable_symbol->symbol, this->target))
{
add_error<type_requirement_error>(variable_identifier.id().position(),
found.value(), type_requirement_error::kind::zero_sized);
@@ -834,7 +835,9 @@ namespace elna::boot
}
for (const auto& variable_identifier : declaration->identifiers)
{
- auto variable_symbol = this->bag.lookup(variable_identifier.name())->is_variable();
+ const std::shared_ptr<variable_info> variable_symbol =
+ this->bag.lookup(variable_identifier.name())->is_variable();
+
if (!is_assignable_from(variable_symbol->symbol, declaration->initializer->type_decoration))
{
add_error<type_mismatch_error>(declaration->initializer->position(),
@@ -869,7 +872,7 @@ namespace elna::boot
void type_analysis_visitor::visit(for_statement *statement)
{
statement->range().accept(this);
- auto resolved_range = resolve_underlying_type(statement->range().type_decoration);
+ const type resolved_range = resolve_underlying_type(statement->range().type_decoration);
if (!get_range_base_type(resolved_range))
{
@@ -923,9 +926,10 @@ namespace elna::boot
void type_analysis_visitor::visit(type_declaration *declaration)
{
walking_visitor::visit(declaration);
- auto unresolved_type = this->bag.lookup(declaration->identifier.name())->is_type()->symbol.get<alias_type>();
+ const std::shared_ptr<alias_type> unresolved_type =
+ this->bag.lookup(declaration->identifier.name())->is_type()->symbol.get<alias_type>();
- if (auto generic = unresolved_type->referent.get<generic_type>())
+ if (const auto generic = unresolved_type->referent.get<generic_type>())
{
check_parameters_used(declaration->position(), declaration->identifier.name(),
generic->parameters, generic->referent);
@@ -933,11 +937,11 @@ namespace elna::boot
}
const type referent = resolve_aliases(unresolved_type->referent);
- if (auto record = referent.get<record_type>())
+ if (const auto record = referent.get<record_type>())
{
for (const auto& [field_name, field] : record->fields)
{
- if (auto opaque = find_opaque_type(field.field_type))
+ if (const auto opaque = find_opaque_type(field.field_type))
{
add_error<type_requirement_error>(declaration->position(),
opaque.value(), type_requirement_error::kind::opaque_field);
@@ -949,27 +953,27 @@ namespace elna::boot
}
}
}
- else if (auto array = referent.get<array_type>())
+ else if (const auto array = referent.get<array_type>())
{
- if (auto opaque = find_opaque_type(array->base))
+ if (const auto opaque = find_opaque_type(array->base))
{
add_error<type_requirement_error>(declaration->position(),
opaque.value(), type_requirement_error::kind::opaque_element);
}
}
- else if (auto slice = referent.get<slice_type>())
+ else if (const auto slice = referent.get<slice_type>())
{
- if (auto opaque = find_opaque_type(slice->base))
+ if (const auto opaque = find_opaque_type(slice->base))
{
add_error<type_requirement_error>(declaration->position(),
opaque.value(), type_requirement_error::kind::opaque_element);
}
}
- else if (auto procedure = referent.get<procedure_type>())
+ else if (const auto procedure = referent.get<procedure_type>())
{
for (const type& parameter : procedure->parameters)
{
- if (auto opaque = find_opaque_type(parameter))
+ if (const auto opaque = find_opaque_type(parameter))
{
add_error<type_requirement_error>(declaration->position(),
opaque.value(), type_requirement_error::kind::opaque_parameter);
@@ -982,7 +986,7 @@ namespace elna::boot
}
if (!procedure->return_type.proper_type.empty())
{
- if (auto opaque = find_opaque_type(procedure->return_type.proper_type))
+ if (const auto opaque = find_opaque_type(procedure->return_type.proper_type))
{
add_error<type_requirement_error>(declaration->position(),
opaque.value(), type_requirement_error::kind::opaque_return);
@@ -1001,7 +1005,8 @@ namespace elna::boot
{
if (expression->base.has_value())
{
- auto const base_symbol = this->bag.lookup(expression->base.value().name());
+ const std::shared_ptr<info> base_symbol = this->bag.lookup(expression->base.value().name());
+
if (base_symbol == nullptr || base_symbol->is_type() == nullptr)
{
add_error<type_requirement_error>(expression->position(),
@@ -1009,7 +1014,7 @@ namespace elna::boot
}
else
{
- type const base_type = erase_generic(base_symbol->is_type()->symbol);
+ const type base_type = erase_generic(base_symbol->is_type()->symbol);
if (base_type.get<record_type>() == nullptr)
{
add_error<type_requirement_error>(expression->position(),
@@ -1032,23 +1037,23 @@ namespace elna::boot
{
return true;
}
- if (auto pointer = subject.get<pointer_type>())
+ else if (const auto pointer = subject.get<pointer_type>())
{
return occurs_in(parameter, pointer->base);
}
- if (auto slice = subject.get<slice_type>())
+ else if (const auto slice = subject.get<slice_type>())
{
return occurs_in(parameter, slice->base);
}
- if (auto array = subject.get<array_type>())
+ else if (const auto array = subject.get<array_type>())
{
return occurs_in(parameter, array->base);
}
- if (auto qualified = subject.get<constant_type>())
+ else if (const auto qualified = subject.get<constant_type>())
{
return occurs_in(parameter, qualified->unqualified);
}
- if (auto record = subject.get<record_type>())
+ else if (const auto record = subject.get<record_type>())
{
for (const auto& [field_name, field] : record->fields)
{
@@ -1059,7 +1064,7 @@ namespace elna::boot
}
return !record->base.empty() && occurs_in(parameter, record->base);
}
- if (auto procedure = subject.get<procedure_type>())
+ else if (const auto procedure = subject.get<procedure_type>())
{
for (const type& parameter_type : procedure->parameters)
{
@@ -1071,7 +1076,7 @@ namespace elna::boot
return !procedure->return_type.proper_type.empty()
&& occurs_in(parameter, procedure->return_type.proper_type);
}
- if (auto instance = subject.get<instantiated_type>())
+ else if (const auto instance = subject.get<instantiated_type>())
{
for (const type& argument : instance->arguments)
{
@@ -1112,7 +1117,7 @@ namespace elna::boot
const type left = resolve_aliases(declared);
const type right = resolve_aliases(actual);
- if (auto parameter = left.get<parameter_type>())
+ if (const auto parameter = left.get<parameter_type>())
{
for (std::size_t i = 0; i < parameters.size(); ++i)
{
@@ -1125,40 +1130,40 @@ namespace elna::boot
}
return true;
}
- if (auto left_pointer = left.get<pointer_type>())
+ else if (const auto left_pointer = left.get<pointer_type>())
{
- auto right_pointer = right.get<pointer_type>();
+ const std::shared_ptr<pointer_type> right_pointer = right.get<pointer_type>();
return right_pointer != nullptr
&& bind_arguments(parameters, bindings, left_pointer->base, right_pointer->base);
}
- if (auto left_slice = left.get<slice_type>())
+ else if (const auto left_slice = left.get<slice_type>())
{
- auto right_slice = right.get<slice_type>();
+ const std::shared_ptr<slice_type> right_slice = right.get<slice_type>();
return right_slice != nullptr
&& bind_arguments(parameters, bindings, left_slice->base, right_slice->base);
}
- if (auto left_array = left.get<array_type>())
+ else if (const auto left_array = left.get<array_type>())
{
- auto right_array = right.get<array_type>();
+ const std::shared_ptr<array_type> right_array = right.get<array_type>();
return right_array != nullptr
&& bind_arguments(parameters, bindings, left_array->base, right_array->base);
}
- if (auto left_constant = left.get<constant_type>())
+ else if (const auto left_constant = left.get<constant_type>())
{
- auto right_constant = right.get<constant_type>();
+ const std::shared_ptr<constant_type> right_constant = right.get<constant_type>();
return right_constant != nullptr
- && bind_arguments(parameters, bindings,
- left_constant->unqualified, right_constant->unqualified);
+ && bind_arguments(parameters, bindings, left_constant->unqualified, right_constant->unqualified);
}
- if (auto left_instance = left.get<instantiated_type>())
+ else if (const auto left_instance = left.get<instantiated_type>())
{
for (type candidate = right; !candidate.empty(); candidate = base_of(candidate))
{
- auto right_instance = resolve_aliases(candidate).get<instantiated_type>();
+ const std::shared_ptr<instantiated_type> right_instance =
+ resolve_aliases(candidate).get<instantiated_type>();
if (right_instance == nullptr
|| !(left_instance->generic == right_instance->generic)
@@ -1178,9 +1183,9 @@ namespace elna::boot
}
return false;
}
- if (auto left_procedure = left.get<procedure_type>())
+ else if (const auto left_procedure = left.get<procedure_type>())
{
- auto right_procedure = right.get<procedure_type>();
+ const std::shared_ptr<procedure_type> right_procedure = right.get<procedure_type>();
if (right_procedure == nullptr
|| left_procedure->parameters.size() != right_procedure->parameters.size())
@@ -1281,7 +1286,7 @@ namespace elna::boot
}
const type denoted = expression->type_decoration;
- if (auto instance = denoted.get<instantiated_type>())
+ if (const auto instance = denoted.get<instantiated_type>())
{
std::shared_ptr<generic_type> const generic = unwrap_generic(instance->generic);
@@ -1404,7 +1409,7 @@ namespace elna::boot
{
// Inference reads the argument types, so they are decorated
// before the parameter types they will be checked against exist.
- for (expression *argument : call->arguments)
+ for (expression *const argument : call->arguments)
{
argument->accept(this);
}
@@ -1414,13 +1419,13 @@ namespace elna::boot
// Name analysis decorated the call with the declared return
// type, which still mentions the parameters inference has
// just bound.
- if (auto substituted = callable_type.get<procedure_type>())
+ if (const auto substituted = callable_type.get<procedure_type>())
{
call->type_decoration = substituted->return_type.proper_type;
}
}
}
- if (auto procedure = callable_type.get<procedure_type>())
+ if (const auto procedure = callable_type.get<procedure_type>())
{
std::vector<expression *>::const_iterator argument_iterator = std::cbegin(call->arguments);
std::vector<type>::const_iterator type_iterator = std::cbegin(procedure->parameters);
@@ -1455,7 +1460,7 @@ namespace elna::boot
if (call->arguments.size() < procedure->parameters.size()
|| (!procedure->variadic && call->arguments.size() > procedure->parameters.size()))
{
- if (auto *procedure_name = call->callable().is_named())
+ if (const auto *procedure_name = call->callable().is_named())
{
add_error<argument_count_error>(call->position(),
argument_count_error::kind::call, procedure_name->name,
@@ -1480,7 +1485,7 @@ namespace elna::boot
void type_analysis_visitor::visit(record_constructor_expression *expression)
{
- auto record = erase_generic(expression->type_decoration).get<record_type>();
+ const std::shared_ptr<record_type> record = erase_generic(expression->type_decoration).get<record_type>();
if (record == nullptr)
{
@@ -1507,7 +1512,8 @@ namespace elna::boot
void type_analysis_visitor::visit(array_constructor_expression *expression)
{
- auto array = resolve_underlying_type(expression->type_decoration).get<array_type>();
+ const std::shared_ptr<array_type> array =
+ resolve_underlying_type(expression->type_decoration).get<array_type>();
if (array == nullptr)
{
@@ -1518,7 +1524,7 @@ namespace elna::boot
}
// The first element of the array literal determines the array type and
// does not have to be checked.
- for (auto *element : expression->elements | std::views::drop(1))
+ for (const auto *element : expression->elements | std::views::drop(1))
{
if (!is_assignable_from(array->base, element->type_decoration))
{
@@ -1548,7 +1554,7 @@ namespace elna::boot
{
walking_visitor::visit(expression);
- auto resolved_base = resolve_underlying_type(expression->base().type_decoration);
+ const type resolved_base = resolve_underlying_type(expression->base().type_decoration);
if (resolved_base.get<array_type>() == nullptr
&& resolved_base.get<slice_type>() == nullptr)
{
@@ -1566,7 +1572,7 @@ namespace elna::boot
{
walking_visitor::visit(expression);
- auto operation = expression->operation();
+ const unary_operator operation = expression->operation();
type const resolved = resolve_underlying_type(expression->operand().type_decoration);
if (operation == unary_operator::plus || operation == unary_operator::minus)
@@ -1595,14 +1601,11 @@ namespace elna::boot
type_mismatch_error::unary{ .operation = operation });
}
}
- else if (operation == unary_operator::reference)
+ else if (operation == unary_operator::reference && !is_addressable(expression->operand()))
{
- if (!is_addressable(expression->operand()))
- {
- add_error<type_requirement_error>(expression->position(),
- expression->operand().type_decoration,
- type_requirement_error::kind::not_addressable);
- }
+ add_error<type_requirement_error>(expression->position(),
+ expression->operand().type_decoration,
+ type_requirement_error::kind::not_addressable);
}
}
@@ -1634,8 +1637,8 @@ namespace elna::boot
opaque.value(), type_requirement_error::kind::opaque_cast);
return;
}
- auto source = resolve_underlying_type(expression->value().type_decoration);
- auto target = resolve_underlying_type(expression->type_decoration);
+ const type source = resolve_underlying_type(expression->value().type_decoration);
+ const type target = resolve_underlying_type(expression->type_decoration);
if (source != target // const cast.
&& (!is_scalar_type(source) || !is_scalar_type(target))
@@ -1651,7 +1654,7 @@ namespace elna::boot
{
walking_visitor::visit(expression);
- auto operation = expression->operation();
+ const binary_operator operation = expression->operation();
type const lhs_resolved = resolve_underlying_type(expression->lhs().type_decoration);
type const rhs_resolved = resolve_underlying_type(expression->rhs().type_decoration);
bool valid = false;
@@ -1804,7 +1807,7 @@ namespace elna::boot
add_error<trait_error>(trait->name.position(), trait->name.name(),
trait_error::unsupported_type{ trait->types.front() });
}
- else if (auto *field = trait->arguments.at(1)->is_named())
+ else if (const auto *field = trait->arguments.at(1)->is_named())
{
if (erase_generic(trait->types.front()).get<record_type>() == nullptr)
{
diff --git a/boot/validation.cc b/boot/validation.cc
index facef04..dda3af7 100644
--- a/boot/validation.cc
+++ b/boot/validation.cc
@@ -64,10 +64,10 @@ namespace elna::boot
}
if (unit->entry_point.has_value())
{
- auto entry_point = this->bag.lookup("")->is_procedure();
+ const std::shared_ptr<procedure_info> entry_point = this->bag.lookup("")->is_procedure();
this->bag.enter(entry_point->scope);
- visit_statements(unit->entry_point->statements);
+ visit_statements(unit->entry_point.value());
this->bag.leave();
}
}
@@ -84,7 +84,9 @@ namespace elna::boot
{
if (declaration->body.has_value())
{
- auto procedure = this->bag.lookup(declaration->identifier.name())->is_procedure();
+ const std::shared_ptr<procedure_info> procedure =
+ this->bag.lookup(declaration->identifier.name())->is_procedure();
+
this->bag.enter(procedure->scope);
visit_statements(declaration->body.value().statements);
this->bag.leave();