aboutsummaryrefslogtreecommitdiff
path: root/boot/semantic.cc
diff options
context:
space:
mode:
Diffstat (limited to 'boot/semantic.cc')
-rw-r--r--boot/semantic.cc80
1 files changed, 42 insertions, 38 deletions
diff --git a/boot/semantic.cc b/boot/semantic.cc
index 97c316a..f46dce9 100644
--- a/boot/semantic.cc
+++ b/boot/semantic.cc
@@ -288,37 +288,6 @@ namespace elna::boot
walking_visitor::visit(expression);
}
- std::size_t type_analysis_visitor::match_record_fields(
- const std::shared_ptr<record_type>& record,
- std::vector<expression *>::const_iterator& argument_it,
- const std::vector<expression *>::const_iterator& argument_end)
- {
- std::size_t expected = 0;
-
- if (!record->base.empty())
- {
- if (auto base = inner_aliased_type(record->base).get<record_type>())
- {
- expected += match_record_fields(base, argument_it, argument_end);
- }
- }
- for (auto& field : record->fields)
- {
- ++expected;
- if (argument_it != argument_end)
- {
- (*argument_it)->accept(this);
- if (!is_assignable_from(field.second, (*argument_it)->type_decoration))
- {
- add_error<type_expectation_error>(type_expectation_error::kind::argument,
- (*argument_it)->position());
- }
- ++argument_it;
- }
- }
- return expected;
- }
-
void type_analysis_visitor::visit(procedure_call *call)
{
call->callable().accept(this);
@@ -346,16 +315,30 @@ namespace elna::boot
call->arguments.size(), call->position());
}
}
- else if (auto callable_record = inner_aliased_type(call->type_decoration).get<record_type>())
- {
- auto argument_it = std::cbegin(call->arguments);
- auto argument_end = std::cend(call->arguments);
+ }
- std::size_t expected = match_record_fields(callable_record, argument_it, argument_end);
+ void type_analysis_visitor::visit(record_constructor_expression *expression)
+ {
+ auto record = inner_aliased_type(expression->type_decoration).get<record_type>();
- if (call->arguments.size() != expected)
+ if (record == nullptr)
+ {
+ add_error<type_expectation_error>(type_expectation_error::kind::result, expression->position());
+ return;
+ }
+ for (const field_initializer& initializer : expression->field_initializers)
+ {
+ for (const type_field& field : record->fields)
{
- add_error<argument_count_error>(expected, call->arguments.size(), call->position());
+ if (field.first == initializer.name)
+ {
+ if (!is_assignable_from(field.second, initializer.value->type_decoration))
+ {
+ add_error<type_expectation_error>(type_expectation_error::kind::argument,
+ initializer.value->position());
+ }
+ break;
+ }
}
}
}
@@ -584,6 +567,27 @@ namespace elna::boot
this->current_type = type(result_type);
}
+ void name_analysis_visitor::visit(record_constructor_expression *expression)
+ {
+ if (auto type_symbol = this->bag.lookup(expression->type_name))
+ {
+ if (auto type_info = type_symbol->is_type())
+ {
+ expression->type_decoration = type_info->symbol;
+ }
+ }
+ for (const field_initializer& initializer : expression->field_initializers)
+ {
+ initializer.value->accept(this);
+ if (!expression->type_decoration.empty()
+ && lookup_field(expression->type_decoration, initializer.name).empty())
+ {
+ add_error<declaration_error>(declaration_error::kind::undeclared,
+ initializer.name, expression->position());
+ }
+ }
+ }
+
void name_analysis_visitor::visit(procedure_type_expression *expression)
{
std::shared_ptr<procedure_type> result_type =