aboutsummaryrefslogtreecommitdiff
path: root/boot/type_check.cc
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-07-21 21:27:03 +0200
committerEugen Wissner <belka@caraus.de>2026-07-21 21:27:03 +0200
commit5cc2947143f2a6ebd4ef1ae4d25ab956b87de808 (patch)
tree0d4489b298da3be04ed4bce117f616468146a0f8 /boot/type_check.cc
parent44d6e8a27294e5ca7300ab11900011b73d9336d4 (diff)
downloadelna-5cc2947143f2a6ebd4ef1ae4d25ab956b87de808.tar.gz
Redefine strings as slice of constant charactersHEADcpp
Diffstat (limited to 'boot/type_check.cc')
-rw-r--r--boot/type_check.cc254
1 files changed, 171 insertions, 83 deletions
diff --git a/boot/type_check.cc b/boot/type_check.cc
index 5d0c7a6..7989925 100644
--- a/boot/type_check.cc
+++ b/boot/type_check.cc
@@ -56,72 +56,6 @@ namespace elna::boot
+ "', because it is constant or contains constant members";
}
- field_not_found_error::field_not_found_error(const identifier& field_name,
- type composite_type)
- : error(field_name.position()), field_name(field_name.name()), composite_type(std::move(composite_type))
- {
- }
-
- std::string field_not_found_error::what() const
- {
- type const resolved = resolve_underlying_type(composite_type);
- bool const is_enum = resolved.get<enumeration_type>() != nullptr;
- bool const is_record = resolved.get<record_type>() != nullptr;
-
- if (is_enum || is_record)
- {
- std::string message = is_enum ? "Enumeration" : "Record";
-
- if (auto alias = composite_type.get<alias_type>())
- {
- message += " '" + alias->name + "'";
- }
- message += " does not have a ";
- message += is_enum ? "member" : "field";
- message += " named '" + field_name + "'";
- return message;
- }
- return "Type '" + composite_type.to_string()
- + "' does not have a field named '" + field_name + "'";
- }
-
- duplicate_member_error::duplicate_member_error(const boot::identifier& member_name,
- type aggregate, std::optional<source_position> original,
- std::optional<std::string> base_name)
- : error(member_name.position()), member_name(member_name.name()), aggregate(std::move(aggregate)),
- original(original), base_name(std::move(base_name))
- {
- }
-
- std::string duplicate_member_error::what() const
- {
- type const resolved = resolve_underlying_type(aggregate);
- bool const is_enum = resolved.get<enumeration_type>() != nullptr;
- std::string const kind = is_enum ? "member" : "field";
- std::string message = is_enum ? "Enumeration" : "Record";
-
- if (auto alias = aggregate.get<alias_type>())
- {
- message += " '" + alias->name + "'";
- }
- message += " already has a " + kind + " named '" + member_name + "'";
-
- if (base_name.has_value())
- {
- message += " (defined in base type '" + *base_name + "')";
- }
- return message;
- }
-
- std::optional<std::pair<std::string, source_position>> duplicate_member_error::note() const
- {
- if (original.has_value() && original->start().available())
- {
- return std::make_pair("previously declared here", *original);
- }
- return std::nullopt;
- }
-
cyclic_declaration_error::cyclic_declaration_error(const std::vector<std::string>& cycle,
const source_position position)
: error(position), cycle(cycle)
@@ -189,18 +123,6 @@ namespace elna::boot
}
}
- unsupported_trait_type_error::unsupported_trait_type_error(const identifier& trait,
- type actual)
- : error(trait.position()), actual(std::move(actual)), trait_name(trait.name())
- {
- }
-
- std::string unsupported_trait_type_error::what() const
- {
- return "Type '" + actual.to_string()
- + "' does not support trait '#" + trait_name + "'";
- }
-
unary_operation_error::unary_operation_error(const source_position position,
type actual, unary_operator operation)
: error(position), actual(std::move(actual)), op(operation)
@@ -215,6 +137,8 @@ namespace elna::boot
case reference:
return '@';
case negation:
+ case bitwise_negation:
+ case logical_negation:
return '~';
case minus:
return '-';
@@ -368,10 +292,36 @@ namespace elna::boot
return verdict::pass;
}
+ 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>();
+
+ 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 can be added to the element type, but not removed.
+ if (assignee_element_const != nullptr
+ && assignee_element_const->unqualified == assignment_slice->base)
+ {
+ return verdict::accept;
+ }
+ if (assignment_element_const != nullptr && assignee_element_const == nullptr)
+ {
+ return verdict::reject;
+ }
+ return verdict::pass;
+ }
+
bool assign_check::run()
{
for (auto handler : {&assign_check::guard_const_laundering,
&assign_check::check_exact_match,
+ &assign_check::check_slice_conversion,
&assign_check::check_pointer_hatch,
&assign_check::check_pointer_conversion})
{
@@ -534,10 +484,18 @@ namespace elna::boot
{
if (expression->base.has_value())
{
- type const base_type = resolve_underlying_type(this->bag.lookup(expression->base.value().name())->is_type()->symbol);
- if (base_type.get<record_type>() == nullptr)
+ auto const base_symbol = this->bag.lookup(expression->base.value().name());
+ if (base_symbol == nullptr || base_symbol->is_type() == nullptr)
{
- add_error<base_type_error>(base_type, expression->position());
+ add_error<base_type_error>(type(), expression->position());
+ }
+ else
+ {
+ type const base_type = resolve_underlying_type(base_symbol->is_type()->symbol);
+ if (base_type.get<record_type>() == nullptr)
+ {
+ add_error<base_type_error>(base_type, expression->position());
+ }
}
}
walking_visitor::visit(expression);
@@ -571,6 +529,12 @@ namespace elna::boot
call->arguments.size(), call->position());
}
}
+ else if (!call->callable().type_decoration.empty())
+ {
+ add_error<type_mismatch_error>(call->position(),
+ type(std::make_shared<procedure_type>()),
+ call->callable().type_decoration);
+ }
}
void type_analysis_visitor::visit(record_constructor_expression *expression)
@@ -660,12 +624,136 @@ namespace elna::boot
}
else if (operation == unary_operator::negation)
{
- if (!is_primitive_type(resolved, "Bool")
- && !is_integral_type(resolved))
+ if (is_primitive_type(resolved, "Bool"))
+ {
+ expression->operation(unary_operator::logical_negation);
+ }
+ else if (is_integral_type(resolved))
+ {
+ expression->operation(unary_operator::bitwise_negation);
+ }
+ else
{
add_error<unary_operation_error>(expression->position(),
expression->operand().type_decoration, operation);
}
}
+ else if (operation == unary_operator::reference)
+ {
+ auto *designator = expression->operand().is_designator();
+ if (designator == nullptr || designator->is_slicing() != nullptr)
+ {
+ add_error<unary_operation_error>(expression->position(),
+ expression->operand().type_decoration, operation);
+ }
+ }
+ }
+
+ binary_operation_error::binary_operation_error(const source_position position,
+ type left, type right, binary_operator operation)
+ : error(position), left(std::move(left)), right(std::move(right)), op(operation)
+ {
+ }
+
+ std::string binary_operation_error::what() const
+ {
+ return "Invalid operands of type '" + left.to_string()
+ + "' and '" + right.to_string()
+ + "' for operator " + print_binary_operator(op);
+ }
+
+ void type_analysis_visitor::visit(binary_expression *expression)
+ {
+ walking_visitor::visit(expression);
+
+ auto 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;
+
+ switch (operation)
+ {
+ using enum binary_operator;
+ case sum:
+ valid = (is_any_pointer_type(lhs_resolved) && is_integral_type(rhs_resolved))
+ || (is_integral_type(lhs_resolved) && is_any_pointer_type(rhs_resolved))
+ || (is_numeric_type(lhs_resolved) && lhs_resolved == rhs_resolved);
+ break;
+ case subtraction:
+ valid = (is_any_pointer_type(lhs_resolved) && is_integral_type(rhs_resolved))
+ || (is_any_pointer_type(lhs_resolved) && is_any_pointer_type(rhs_resolved))
+ || (is_numeric_type(lhs_resolved) && lhs_resolved == rhs_resolved);
+ break;
+ case division:
+ case remainder:
+ case multiplication:
+ valid = is_numeric_type(lhs_resolved) && lhs_resolved == rhs_resolved;
+ break;
+ case less:
+ case greater:
+ case less_equal:
+ case greater_equal:
+ valid = (is_numeric_type(lhs_resolved) && lhs_resolved == rhs_resolved)
+ || (is_any_pointer_type(lhs_resolved) && is_any_pointer_type(rhs_resolved));
+ break;
+ case conjunction:
+ case disjunction:
+ case exclusive_disjunction:
+ if (is_primitive_type(lhs_resolved, "Bool") && lhs_resolved == rhs_resolved)
+ {
+ switch (operation)
+ {
+ case conjunction:
+ expression->operation(logical_conjunction);
+ break;
+ case disjunction:
+ expression->operation(logical_disjunction);
+ break;
+ case exclusive_disjunction:
+ expression->operation(logical_exclusive_disjunction);
+ break;
+ default:
+ break;
+ }
+ valid = true;
+ }
+ else if (is_integral_type(lhs_resolved) && lhs_resolved == rhs_resolved)
+ {
+ switch (operation)
+ {
+ case conjunction:
+ expression->operation(bitwise_conjunction);
+ break;
+ case disjunction:
+ expression->operation(bitwise_disjunction);
+ break;
+ case exclusive_disjunction:
+ expression->operation(bitwise_exclusive_disjunction);
+ break;
+ default:
+ break;
+ }
+ valid = true;
+ }
+ break;
+ case equals:
+ case not_equals:
+ valid = lhs_resolved == rhs_resolved
+ || (is_primitive_type(lhs_resolved, "Pointer") && is_any_pointer_type(rhs_resolved))
+ || (is_any_pointer_type(lhs_resolved) && is_primitive_type(rhs_resolved, "Pointer"))
+ || (lhs_resolved.get<slice_type>() && rhs_resolved.get<slice_type>())
+ || (lhs_resolved.get<record_type>() && rhs_resolved.get<record_type>());
+ break;
+ case shift_left:
+ case shift_right:
+ valid = is_integral_type(lhs_resolved)
+ && is_primitive_type(rhs_resolved, "Word");
+ break;
+ }
+ if (!valid)
+ {
+ add_error<binary_operation_error>(expression->position(),
+ expression->lhs().type_decoration, expression->rhs().type_decoration, operation);
+ }
}
}