From a0e1740227535adc3151c02eb102c4f96b4f9731 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Fri, 17 Jul 2026 10:18:58 +0200 Subject: Implement type constness --- boot/ast.cc | 101 ++++++++--------- boot/parser.yy | 28 ++--- boot/semantic.cc | 338 ++++++++++++++++++++++++++----------------------------- boot/symbol.cc | 91 +++++++++++---- 4 files changed, 285 insertions(+), 273 deletions(-) (limited to 'boot') diff --git a/boot/ast.cc b/boot/ast.cc index 37e89ac..3454cce 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -29,6 +29,11 @@ namespace elna::boot __builtin_unreachable(); } + void empty_visitor::visit(constant_type_expression *) + { + __builtin_unreachable(); + } + void empty_visitor::visit(type_declaration *) { __builtin_unreachable(); @@ -54,11 +59,6 @@ namespace elna::boot __builtin_unreachable(); } - void empty_visitor::visit(constant_declaration *) - { - __builtin_unreachable(); - } - void empty_visitor::visit(procedure_declaration *) { __builtin_unreachable(); @@ -210,10 +210,6 @@ namespace elna::boot } if (declaration->body.has_value()) { - for (constant_declaration *const constant : declaration->body.value().constants) - { - constant->accept(this); - } for (variable_declaration *const variable : declaration->body.value().variables) { variable->accept(this); @@ -336,10 +332,6 @@ namespace elna::boot { variable->accept(this); } - for (constant_declaration *const constant : unit->constants) - { - constant->accept(this); - } for (procedure_declaration *const procedure : unit->procedures) { procedure->accept(this); @@ -364,17 +356,17 @@ namespace elna::boot } } - void walking_visitor::visit(constant_declaration *declaration) + void walking_visitor::visit(array_type_expression *expression) { - declaration->initializer().accept(this); + expression->base().accept(this); } - void walking_visitor::visit(array_type_expression *expression) + void walking_visitor::visit(pointer_type_expression *expression) { expression->base().accept(this); } - void walking_visitor::visit(pointer_type_expression *expression) + void walking_visitor::visit(constant_type_expression *expression) { expression->base().accept(this); } @@ -557,6 +549,11 @@ namespace elna::boot return nullptr; } + constant_type_expression *type_expression::is_constant() + { + return nullptr; + } + record_type_expression *type_expression::is_record() { return nullptr; @@ -624,6 +621,32 @@ namespace elna::boot return *m_base; } + constant_type_expression::constant_type_expression(const source_position position, + type_expression *base) + : node(position), m_base(base) + { + } + + constant_type_expression::~constant_type_expression() + { + delete m_base; + } + + void constant_type_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + constant_type_expression *constant_type_expression::is_constant() + { + return this; + } + + type_expression& constant_type_expression::base() + { + return *m_base; + } + record_type_expression::record_type_expression(const source_position position, std::vector&& fields) : node(position), fields(std::move(fields)) @@ -753,27 +776,6 @@ namespace elna::boot { } - constant_declaration::constant_declaration(const source_position position, identifier_definition identifier, - expression *initializer) - : declaration(position, identifier), m_initializer(initializer) - { - } - - void constant_declaration::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - expression& constant_declaration::initializer() - { - return *m_initializer; - } - - constant_declaration::~constant_declaration() - { - delete m_initializer; - } - procedure_type_expression::procedure_type_expression(const source_position position, std::vector&& parameters, return_t return_type) : node(position), return_type(return_type), parameters(std::move(parameters)) @@ -863,17 +865,15 @@ namespace elna::boot return *m_underlying_type; } - procedure_body::procedure_body(std::vector&& constants, - std::vector&& variables, std::vector&& entry_point, - expression *return_expr) - : constants(std::move(constants)), variables(std::move(variables)), - entry_point(std::move(entry_point)), return_expression(return_expr) + procedure_body::procedure_body(std::vector&& variables, + std::vector&& entry_point, expression *return_expression) + : variables(std::move(variables)), + entry_point(std::move(entry_point)), return_expression(return_expression) { } procedure_body::procedure_body(procedure_body&& that) - : constants(std::move(const_cast&>(that.constants))), - variables(std::move(const_cast&>(that.variables))), + : variables(std::move(const_cast&>(that.variables))), entry_point(std::move(const_cast&>(that.entry_point))), return_expression(that.return_expression) { @@ -889,27 +889,22 @@ namespace elna::boot { delete variable; } - for (constant_declaration *constant : this->constants) - { - delete constant; - } } unit::unit(const source_position position) - : node(position), procedure_body(std::vector{}, - std::vector{}, std::vector{}, nullptr) + : node(position), + procedure_body(std::vector{}, std::vector{}, nullptr) { } unit::unit(const source_position position, std::vector&& imports, - std::vector&& constants, std::vector&& types, std::vector&& variables, std::vector&& procedures, std::vector&& entry_point) : node(position), - procedure_body(std::move(constants), std::move(variables), std::move(entry_point)), + procedure_body(std::move(variables), std::move(entry_point)), imports(std::move(imports)), types(std::move(types)), procedures(std::move(procedures)) { } diff --git a/boot/parser.yy b/boot/parser.yy index c34c905..1dd42a8 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -129,8 +129,6 @@ along with GCC; see the file COPYING3. If not see %type > case_labels; %type switch_case; %type > switch_cases; -%type constant_declaration; -%type > constant_part constant_declarations; %type variable_declaration; %type > variable_declarations variable_part; %type type_expression; @@ -166,14 +164,14 @@ along with GCC; see the file COPYING3. If not see %type > import_declarations import_part; %% program: - import_part constant_part type_part variable_part procedure_part statement_part "end" "." + import_part type_part variable_part procedure_part statement_part "end" "." { - boot::unit *tree = new boot::unit(boot::make_position(@$), $1, $2, $3, $4, $5, $6); + boot::unit *tree = new boot::unit(boot::make_position(@$), $1, $2, $3, $4, $5); driver.tree.reset(tree); } procedure_body: - constant_part variable_part statement_part procedure_return - { $$ = std::make_unique($1, $2, $3, $4); } + variable_part statement_part procedure_return + { $$ = std::make_unique($1, $2, $3); } statement_part: /* no statements */ {} @@ -444,6 +442,10 @@ type_expression: { $$ = new boot::array_type_expression(boot::make_position(@$), $4, $2); } + | "const" type_expression + { + $$ = new boot::constant_type_expression(boot::make_position(@$), $2); + } | "^" type_expression { $$ = new boot::pointer_type_expression(boot::make_position(@$), $2); @@ -501,20 +503,6 @@ variable_declarations: variable_part: /* no variable declarations */ {} | "var" variable_declarations { $$ = $2; } -constant_declaration: identifier_definition ":=" expression - { - $$ = new boot::constant_declaration(boot::make_position(@$), std::move(*$1), $3); - } -constant_declarations: - constant_declaration constant_declarations - { - $$ = $2; - $$.insert(std::cbegin($$), $1); - } - | /* no constant definitions */ {} -constant_part: - /* no constant definitions */ {} - | "const" constant_declarations { $$ = $2; } import_declaration: IDENTIFIER "." import_declaration { diff --git a/boot/semantic.cc b/boot/semantic.cc index 9137053..c987cfd 100644 --- a/boot/semantic.cc +++ b/boot/semantic.cc @@ -73,6 +73,18 @@ namespace elna::boot + "', but got '" + actual.to_string() + "'"; } + constant_assignment_error::constant_assignment_error(const source_position position, + type assignee) + : error(position), assignee(assignee) + { + } + + std::string constant_assignment_error::what() const + { + return "Cannot assign to a value of type '" + assignee.to_string() + + "', 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(composite_type) @@ -81,7 +93,7 @@ namespace elna::boot std::string field_not_found_error::what() const { - type resolved = inner_aliased_type(composite_type); + type resolved = resolve_underlying_type(composite_type); bool is_enum = resolved.get() != nullptr; bool is_record = resolved.get() != nullptr; @@ -112,7 +124,7 @@ namespace elna::boot std::string duplicate_member_error::what() const { - type resolved = inner_aliased_type(aggregate); + type resolved = resolve_underlying_type(aggregate); bool is_enum = resolved.get() != nullptr; std::string kind = is_enum ? "member" : "field"; std::string message = is_enum ? "Enumeration" : "Record"; @@ -208,7 +220,7 @@ namespace elna::boot unsupported_trait_type_error::unsupported_trait_type_error(const identifier& trait, type actual) - : error(trait.position()), trait_name(trait.name()), actual(actual) + : error(trait.position()), actual(actual), trait_name(trait.name()) { } @@ -218,6 +230,119 @@ namespace elna::boot + "' does not support trait '#" + trait_name + "'"; } + // Members of a constant aggregate are constant themselves. + static type qualify_member_type(const type& element, const type& aggregate) + { + if (resolve_aliases(aggregate).get() != nullptr + && resolve_aliases(element).get() == nullptr) + { + return type(std::make_shared(element)); + } + else + { + return element; + } + } + + /* + * Whether the type itself is constant or has a constant member at any + * nesting level, so that values of this type cannot be reassigned as a + * whole. Pointers to constants do not make the type itself constant. + */ + static bool contains_constant_member(const type& checked) + { + auto referent = resolve_aliases(checked); + + if (referent.get() != nullptr) + { + return true; + } + else if (auto record = referent.get()) + { + for (const type_field& field : record->fields) + { + if (contains_constant_member(field.second)) + { + return true; + } + } + return !record->base.empty() && contains_constant_member(record->base); + } + else if (auto array = referent.get()) + { + return contains_constant_member(array->base); + } + return false; + } + + bool type_analysis_visitor::check_unresolved_symbol(std::shared_ptr alias, + std::vector& alias_path) + { + if (std::find(std::cbegin(alias_path), std::cend(alias_path), alias->name) != std::cend(alias_path)) + { + return false; + } + alias_path.push_back(alias->name); + + if (auto another_alias = alias->reference.get()) + { + return check_unresolved_symbol(another_alias, alias_path); + } + return true; + } + + bool type_analysis_visitor::is_base_of(const std::shared_ptr& base, + const std::shared_ptr& derived) + { + if (derived != nullptr) + { + if (auto current_record = resolve_underlying_type(derived->base).get()) + { + return current_record == base || is_base_of(base, current_record); + } + } + return false; + } + + bool type_analysis_visitor::is_assignable_from(const type& assignee, const type& assignment) + { + type resolved_assignee = resolve_underlying_type(assignee); + type resolved_assignment = resolve_underlying_type(assignment); + + if (resolved_assignee == resolved_assignment + || (is_primitive_type(resolved_assignee, "Pointer") && is_any_pointer_type(resolved_assignment)) + || (is_primitive_type(resolved_assignment, "Pointer") && is_any_pointer_type(resolved_assignee))) + { + return true; + } + std::shared_ptr assignee_pointer = resolved_assignee.get(); + std::shared_ptr assignment_pointer = resolved_assignment.get(); + + if (assignee_pointer == nullptr || assignment_pointer == nullptr) + { + return false; + } + auto assignee_pointee_const = resolve_aliases(assignee_pointer->base).get(); + auto assignment_pointee_const = resolve_aliases(assignment_pointer->base).get(); + + // Constness can be added at the first indirection level, but not removed. + if (assignee_pointee_const != nullptr + && assignee_pointee_const->unqualified == assignment_pointer->base) + { + return true; + } + if (assignment_pointee_const != nullptr && assignee_pointee_const == nullptr) + { + return false; + } + // A pointer to a record can be assigned to a pointer to its base type. + std::shared_ptr assignee_record = + resolve_underlying_type(assignee_pointer->base).get(); + + return assignee_record != nullptr + && is_base_of(assignee_record, resolve_underlying_type(assignment_pointer->base).get()); + } + type_analysis_visitor::type_analysis_visitor(symbol_bag bag) : error_container(), bag(bag) { @@ -272,7 +397,12 @@ namespace elna::boot { walking_visitor::visit(statement); - if (!is_assignable_from(statement->lvalue().type_decoration, statement->rvalue().type_decoration)) + if (contains_constant_member(statement->lvalue().type_decoration)) + { + add_error(statement->position(), + statement->lvalue().type_decoration); + } + else if (!is_assignable_from(statement->lvalue().type_decoration, statement->rvalue().type_decoration)) { add_error(statement->position(), statement->lvalue().type_decoration, statement->rvalue().type_decoration); @@ -302,7 +432,7 @@ namespace elna::boot void type_analysis_visitor::visit(case_statement *statement) { walking_visitor::visit(statement); - type condition_type = inner_aliased_type(statement->condition().type_decoration); + type condition_type = resolve_underlying_type(statement->condition().type_decoration); for (const switch_case& case_block : statement->cases) { @@ -317,22 +447,6 @@ namespace elna::boot } } - bool type_analysis_visitor::check_unresolved_symbol(std::shared_ptr alias, - std::vector& alias_path) - { - if (std::find(std::cbegin(alias_path), std::cend(alias_path), alias->name) != std::cend(alias_path)) - { - return false; - } - alias_path.push_back(alias->name); - - if (auto another_alias = alias->reference.get()) - { - return check_unresolved_symbol(another_alias, alias_path); - } - return true; - } - void type_analysis_visitor::visit(type_declaration *declaration) { std::vector alias_path; @@ -352,7 +466,7 @@ namespace elna::boot { if (expression->base.has_value()) { - type base_type = inner_aliased_type(this->bag.lookup(expression->base.value().name())->is_type()->symbol); + type base_type = resolve_underlying_type(this->bag.lookup(expression->base.value().name())->is_type()->symbol); if (base_type.get() == nullptr) { add_error(base_type, expression->position()); @@ -393,7 +507,7 @@ namespace elna::boot void type_analysis_visitor::visit(record_constructor_expression *expression) { - auto record = inner_aliased_type(expression->type_decoration).get(); + auto record = resolve_underlying_type(expression->type_decoration).get(); if (record == nullptr) { @@ -422,7 +536,7 @@ namespace elna::boot void type_analysis_visitor::visit(array_constructor_expression *expression) { - auto array = inner_aliased_type(expression->type_decoration).get(); + auto array = resolve_underlying_type(expression->type_decoration).get(); if (array == nullptr) { @@ -490,49 +604,9 @@ namespace elna::boot return this->bag.lookup(name)->is_type()->symbol; } - type name_analysis_visitor::type_of_constant(const constant_info::variant& value) - { - return std::visit([this](auto&& arg) -> type { - using T = std::decay_t; - - if constexpr (std::is_same_v) - { - return lookup_primitive_type("Int"); - } - else if constexpr (std::is_same_v) - { - return lookup_primitive_type("Word"); - } - else if constexpr (std::is_same_v) - { - return lookup_primitive_type("Float"); - } - else if constexpr (std::is_same_v) - { - return lookup_primitive_type("Bool"); - } - else if constexpr (std::is_same_v) - { - return lookup_primitive_type("Char"); - } - else if constexpr (std::is_same_v) - { - return lookup_primitive_type("Pointer"); - } - else if constexpr (std::is_same_v) - { - return lookup_primitive_type("String"); - } - else - { - static_assert(!sizeof(T*), "Unhandled constant type"); - } - }, value); - } - type name_analysis_visitor::lookup_field(const type& composite_type, const std::string& field_name) { - type resolved_type = inner_aliased_type(composite_type); + type resolved_type = resolve_underlying_type(composite_type); if (auto record = resolved_type.get()) { @@ -579,6 +653,12 @@ namespace elna::boot this->current_type = type(std::make_shared(this->current_type)); } + void name_analysis_visitor::visit(constant_type_expression *expression) + { + walking_visitor::visit(expression); + this->current_type = type(std::make_shared(this->current_type)); + } + void name_analysis_visitor::visit(array_type_expression *expression) { walking_visitor::visit(expression); @@ -593,7 +673,7 @@ namespace elna::boot static void collect_field_names(const type& composite_type, std::map& names) { - auto record = inner_aliased_type(composite_type).get(); + auto record = resolve_underlying_type(composite_type).get(); if (record == nullptr) { return; @@ -803,15 +883,6 @@ namespace elna::boot } } - void name_analysis_visitor::visit(constant_declaration *declaration) - { - walking_visitor::visit(declaration); - auto constant_symbol = std::make_shared(this->current_literal); - - constant_symbol->exported = declaration->identifier.exported(); - constant_symbol->position.emplace(declaration->position()); - this->bag.enter(declaration->identifier.name(), constant_symbol); - } void name_analysis_visitor::visit(procedure_declaration *declaration) { @@ -833,10 +904,6 @@ namespace elna::boot ++name_iterator; ++type_iterator; } - for (constant_declaration *const constant : declaration->body.value().constants) - { - constant->accept(this); - } for (variable_declaration *const variable : declaration->body.value().variables) { variable->accept(this); @@ -887,10 +954,6 @@ namespace elna::boot { variable->accept(this); } - for (constant_declaration *const constant : unit->constants) - { - constant->accept(this); - } for (procedure_declaration *const procedure : unit->procedures) { procedure->accept(this); @@ -932,7 +995,7 @@ namespace elna::boot if (!trait->type_decoration.empty()) { - type resolved = inner_aliased_type(trait->type_decoration); + type resolved = resolve_underlying_type(trait->type_decoration); bool is_enum = resolved.get() != nullptr; bool is_integral = false; @@ -1005,7 +1068,7 @@ namespace elna::boot void name_analysis_visitor::visit(array_access_expression *expression) { walking_visitor::visit(expression); - auto resolved_base= inner_aliased_type(expression->base().type_decoration); + auto resolved_base = resolve_underlying_type(expression->base().type_decoration); if (auto array = resolved_base.get()) { @@ -1015,6 +1078,13 @@ namespace elna::boot { expression->type_decoration = lookup_primitive_type("Char"); } + // Elements of a constant array are constant themselves since a static + // array is a holistic type. + if (!expression->type_decoration.empty()) + { + expression->type_decoration = qualify_member_type(expression->type_decoration, + expression->base().type_decoration); + } } void name_analysis_visitor::visit(field_access_expression *expression) @@ -1029,7 +1099,11 @@ namespace elna::boot } if (expression->type_decoration.empty()) { - add_error(expression->field(), + add_error(expression->field(), expression->base().type_decoration); + } + else + { + expression->type_decoration = qualify_member_type(expression->type_decoration, expression->base().type_decoration); } } @@ -1038,7 +1112,7 @@ namespace elna::boot { walking_visitor::visit(expression); - if (auto pointer = inner_aliased_type(expression->base().type_decoration).get()) + if (auto pointer = resolve_underlying_type(expression->base().type_decoration).get()) { expression->type_decoration = pointer->base; } @@ -1068,10 +1142,6 @@ namespace elna::boot { expression->type_decoration = variable_symbol->symbol; } - else if (auto constant_symbol = from_symbol_table->is_constant()) - { - expression->type_decoration = type_of_constant(constant_symbol->symbol); - } else if (auto procedure_symbol = from_symbol_table->is_procedure()) { expression->type_decoration = type(std::make_shared(procedure_symbol->symbol)); @@ -1086,43 +1156,36 @@ namespace elna::boot void name_analysis_visitor::visit(literal *literal) { - this->current_literal = literal->value; literal->type_decoration = lookup_primitive_type("Int"); } void name_analysis_visitor::visit(literal *literal) { - this->current_literal = literal->value; literal->type_decoration = lookup_primitive_type("Word"); } void name_analysis_visitor::visit(literal *literal) { - this->current_literal = literal->value; literal->type_decoration = lookup_primitive_type("Float"); } void name_analysis_visitor::visit(literal *literal) { - this->current_literal = literal->value; literal->type_decoration = lookup_primitive_type("Bool"); } void name_analysis_visitor::visit(literal *literal) { - this->current_literal = literal->value; literal->type_decoration = lookup_primitive_type("Char"); } void name_analysis_visitor::visit(literal *literal) { - this->current_literal = literal->value; literal->type_decoration = lookup_primitive_type("Pointer"); } void name_analysis_visitor::visit(literal *literal) { - this->current_literal = literal->value; literal->type_decoration = lookup_primitive_type("String"); } @@ -1168,10 +1231,6 @@ namespace elna::boot { return; } - for (constant_declaration *const constant : declaration->body.value().constants) - { - constant->accept(this); - } for (variable_declaration *const variable : declaration->body.value().variables) { variable->accept(this); @@ -1189,79 +1248,4 @@ namespace elna::boot } } } - - void declaration_visitor::visit(constant_declaration *declaration) - { - if (declaration->identifier.exported()) - { - add_error(declaration_error::kind::local_export, - declaration->identifier.id()); - } - } - - bool is_base_of(std::shared_ptr base, std::shared_ptr derived) - { - type current = derived->base; - - while (!current.empty()) - { - auto current_record = inner_aliased_type(current).get(); - if (current_record == nullptr) - { - return false; - } - if (current_record == base) - { - return true; - } - current = current_record->base; - } - return false; - } - - bool are_compatible_pointers(type lhs_type, type rhs_type) - { - std::shared_ptr lhs_primitive = lhs_type.get(); - std::shared_ptr rhs_primitive = rhs_type.get(); - - bool lhs_is_primitive_pointer = lhs_primitive != nullptr && lhs_primitive->identifier == "Pointer"; - bool rhs_is_primitive_pointer = rhs_primitive != nullptr && rhs_primitive->identifier == "Pointer"; - - return (lhs_is_primitive_pointer && rhs_type.get() != nullptr) - || (rhs_is_primitive_pointer && lhs_type.get() != nullptr) - || (lhs_is_primitive_pointer && rhs_type.get() != nullptr) - || (rhs_is_primitive_pointer && lhs_type.get() != nullptr) - || (lhs_is_primitive_pointer && rhs_is_primitive_pointer); - } - - bool is_assignable_from(const type& assignee, const type& assignment) - { - type resolved_assignee = inner_aliased_type(assignee); - type resolved_assignment = inner_aliased_type(assignment); - - if (resolved_assignee == resolved_assignment) - { - return true; - } - // If the types do not match, only some pointers can be assigned. - if (are_compatible_pointers(resolved_assignee, resolved_assignment)) - { - return true; - } - std::shared_ptr assignee_pointer = resolved_assignee.get(); - std::shared_ptr assignment_pointer = resolved_assignment.get(); - - if (assignee_pointer == nullptr || assignment_pointer == nullptr) - { - return false; - } - // A pointer to a record can be assigned to a pointer to its base type. - type assignee_pointee = inner_aliased_type(assignee_pointer->base); - type assignment_pointee = inner_aliased_type(assignment_pointer->base); - std::shared_ptr assignee_record = assignee_pointee.get(); - std::shared_ptr assignment_record = assignment_pointee.get(); - - return assignee_record != nullptr && assignment_record != nullptr - && is_base_of(assignee_record, assignment_record); - } } diff --git a/boot/symbol.cc b/boot/symbol.cc index a3a36c1..9985489 100644 --- a/boot/symbol.cc +++ b/boot/symbol.cc @@ -43,6 +43,11 @@ namespace elna::boot { } + type::type(std::shared_ptr constant) + : tag(type_tag::constant), constant(constant) + { + } + type::type(std::shared_ptr array) : tag(type_tag::array), array(array) { @@ -76,6 +81,9 @@ namespace elna::boot case type_tag::pointer: new (&pointer) std::shared_ptr(other.pointer); break; + case type_tag::constant: + new (&constant) std::shared_ptr(other.constant); + break; case type_tag::array: new (&array) std::shared_ptr(other.array); break; @@ -112,6 +120,9 @@ namespace elna::boot case type_tag::pointer: new (&pointer) std::shared_ptr(std::move(other.pointer)); break; + case type_tag::constant: + new (&constant) std::shared_ptr(std::move(other.constant)); + break; case type_tag::array: new (&array) std::shared_ptr(std::move(other.array)); break; @@ -164,6 +175,9 @@ namespace elna::boot case type_tag::pointer: this->pointer.~shared_ptr(); break; + case type_tag::constant: + this->constant.~shared_ptr(); + break; case type_tag::array: this->array.~shared_ptr(); break; @@ -206,6 +220,12 @@ namespace elna::boot return tag == type_tag::array ? this->array : nullptr; } + template<> + std::shared_ptr type::get() const + { + return tag == type_tag::constant ? this->constant : nullptr; + } + template<> std::shared_ptr type::get() const { @@ -225,8 +245,8 @@ namespace elna::boot bool type::operator==(const type& other) const { - type resolved_this = inner_aliased_type(*this); - type resolved_that = inner_aliased_type(other); + type resolved_this = resolve_aliases(*this); + type resolved_that = resolve_aliases(other); if (auto left_record = resolved_this.get()) { @@ -248,6 +268,12 @@ namespace elna::boot return right_pointer != nullptr && left_pointer->base == right_pointer->base; } + if (auto left_const = resolved_this.get()) + { + auto right_const = resolved_that.get(); + + return right_const != nullptr && left_const->unqualified == right_const->unqualified; + } if (auto left_array = resolved_this.get()) { auto right_array = resolved_that.get(); @@ -282,6 +308,8 @@ namespace elna::boot return primitive->identifier; case type_tag::pointer: return "^" + pointer->base.to_string(); + case type_tag::constant: + return "const " + constant->unqualified.to_string(); case type_tag::array: return "[" + std::to_string(array->size) + "]" + array->base.to_string(); case type_tag::record: @@ -328,6 +356,11 @@ namespace elna::boot { } + constant_type::constant_type(type unqualified) + : unqualified(unqualified) + { + } + array_type::array_type(type base, std::uint64_t size) : base(base), size(size) { @@ -367,11 +400,6 @@ namespace elna::boot return nullptr; } - std::shared_ptr info::is_constant() - { - return nullptr; - } - std::shared_ptr info::is_variable() { return nullptr; @@ -403,16 +431,6 @@ namespace elna::boot return this->scope == nullptr; } - constant_info::constant_info(const variant& symbol) - : symbol(symbol) - { - } - - std::shared_ptr constant_info::is_constant() - { - return std::static_pointer_cast(shared_from_this()); - } - variable_info::variable_info(const type symbol, bool is_extern) : symbol(symbol), is_extern(is_extern) { @@ -524,20 +542,47 @@ namespace elna::boot return m_exported; } - type inner_aliased_type(std::shared_ptr alias) + type resolve_underlying_type(std::shared_ptr alias) { - return inner_aliased_type(alias->reference); + return resolve_underlying_type(alias->reference); } - type inner_aliased_type(const type& alias) + type resolve_underlying_type(const type& alias) { - if (auto aliased = alias.get()) + type resolved_alias = resolve_aliases(alias); + + if (auto qualified = resolved_alias.get()) { - return inner_aliased_type(aliased); + return resolve_underlying_type(qualified->unqualified); } else { - return alias; + return resolved_alias; + } + } + + type resolve_aliases(const type& checked) + { + if (auto alias = checked.get()) + { + return resolve_aliases(alias->reference); + } + return checked; + } + + bool is_primitive_type(const type& checked, const std::string& name) + { + if (auto primitive_checked = checked.get()) + { + return primitive_checked->identifier == name; } + return false; + } + + bool is_any_pointer_type(const type& checked) + { + return checked.get() != nullptr + || checked.get() != nullptr + || is_primitive_type(checked, "Pointer"); } } -- cgit v1.2.3