From 52c8ca2c06da93c8d14e80a256e8996c1fa1e885 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Mon, 14 Sep 2026 21:11:03 +0200 Subject: Implement volatile operations --- boot/symbol.cc | 18 ++++++++++++++++++ boot/type_check.cc | 55 +++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 66 insertions(+), 7 deletions(-) (limited to 'boot') diff --git a/boot/symbol.cc b/boot/symbol.cc index 466715b..55f91ea 100644 --- a/boot/symbol.cc +++ b/boot/symbol.cc @@ -401,6 +401,24 @@ namespace elna::boot std::vector{ "condition" }); result->enter("assert", assert_info); + const type load_parameter = type(std::make_shared("T")); + procedure_type volatile_load_symbol{ procedure_type::return_t(load_parameter) }; + volatile_load_symbol.parameters.emplace_back(std::make_shared(load_parameter)); + std::shared_ptr const volatile_load_info = + std::make_shared(volatile_load_symbol, std::vector{ "source" }); + volatile_load_info->parameters.push_back(load_parameter); + result->enter("volatile_load", volatile_load_info); + + const type store_parameter = type(std::make_shared("T")); + procedure_type volatile_store_symbol{ procedure_type::return_t() }; + volatile_store_symbol.parameters.emplace_back(std::make_shared(store_parameter)); + volatile_store_symbol.parameters.push_back(store_parameter); + std::shared_ptr const volatile_store_info = + std::make_shared(volatile_store_symbol, + std::vector{ "target", "value" }); + volatile_store_info->parameters.push_back(store_parameter); + result->enter("volatile_store", volatile_store_info); + return result; } diff --git a/boot/type_check.cc b/boot/type_check.cc index eee5b42..2b82bec 100644 --- a/boot/type_check.cc +++ b/boot/type_check.cc @@ -142,6 +142,11 @@ namespace elna::boot return "Type '" + payload.actual.to_string() + "' cannot be a type argument of '" + this->generic_name + "', it is not a pointer type"; } + else if constexpr (std::is_same_v) + { + return "Type '" + payload.actual.to_string() + "' cannot be a type argument of '" + + this->generic_name + "', it is not a scalar type"; + } else if constexpr (std::is_same_v) { return "Constant type '" + payload.actual.to_string() @@ -1217,23 +1222,50 @@ namespace elna::boot return true; } + /* + * The volatile builtins take the pointee as their type argument, so the + * rule applies to what is loaded or stored rather than to a pointer. + */ + static argument_rule builtin_argument_rule(const std::string& name) + { + if (name == "volatile_load") + { + return argument_rule::scalar; + } + if (name == "volatile_store") + { + return argument_rule::mutable_scalar; + } + return argument_rule::pointer; + } + void type_analysis_visitor::check_arguments(const named_expression& reference, - const std::vector& arguments) + const std::vector& arguments, const argument_rule rule) { for (const type& argument : arguments) { - const type resolved = resolve_aliases(argument); + if (argument.empty()) + { + continue; + } + const type underlying = resolve_underlying_type(argument); - if (resolved.get() != nullptr) + if (rule != argument_rule::scalar + && resolve_aliases(argument).get() != nullptr) { add_error(reference.position(), reference.name, generic_error::constant_argument{ argument }); } - else if (!argument.empty() && !is_any_pointer_type(resolve_underlying_type(argument))) + else if (rule == argument_rule::pointer && !is_any_pointer_type(underlying)) { add_error(reference.position(), reference.name, generic_error::argument_not_pointer{ argument }); } + else if (rule != argument_rule::pointer && !is_scalar_type(underlying)) + { + add_error(reference.position(), reference.name, + generic_error::argument_not_scalar{ argument }); + } } } @@ -1261,7 +1293,8 @@ namespace elna::boot } else if (!expression->arguments.empty()) { - check_arguments(*expression, expression->argument_types); + check_arguments(*expression, expression->argument_types, + builtin_argument_rule(expression->name)); } return; } @@ -1284,7 +1317,7 @@ namespace elna::boot } else { - check_arguments(*expression, expression->argument_types); + check_arguments(*expression, expression->argument_types, argument_rule::pointer); } } else if (std::shared_ptr const generic = unwrap_generic(denoted)) @@ -1335,7 +1368,7 @@ namespace elna::boot return type(); } } - check_arguments(reference, bindings); + check_arguments(reference, bindings, builtin_argument_rule(reference.name)); return substitute(type(std::make_shared(procedure.symbol)), procedure.parameters, bindings); @@ -1396,6 +1429,14 @@ namespace elna::boot } inferred = procedure; callable_type = infer_call(*call, *reference, *procedure); + + // 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()) + { + call->type_decoration = substituted->return_type.proper_type; + } } } if (auto procedure = callable_type.get()) -- cgit v1.2.3