aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-07-17 16:16:23 +0200
committerEugen Wissner <belka@caraus.de>2026-07-17 16:16:23 +0200
commite676e74efbbbf62887b9442326399eebccc4d108 (patch)
tree04c51d56a20dd17bb5091895292079504c1dc13e
parentdb528ae1fbec5219fa34e1b780590eef89e9618c (diff)
downloadelna-e676e74efbbbf62887b9442326399eebccc4d108.tar.gz
Handle base type constness
-rw-r--r--boot/symbol.cc289
-rw-r--r--boot/type_check.cc5
-rw-r--r--gcc/gcc/elna-builtins.cc2
-rw-r--r--include/elna/boot/symbol.h58
-rw-r--r--testsuite/compilable/record_const_base.elna18
5 files changed, 105 insertions, 267 deletions
diff --git a/boot/symbol.cc b/boot/symbol.cc
index bd6ec49..6ad89b7 100644
--- a/boot/symbol.cc
+++ b/boot/symbol.cc
@@ -19,224 +19,72 @@ along with GCC; see the file COPYING3. If not see
namespace elna::boot
{
- type::type()
- {
- }
-
type::type(std::shared_ptr<alias_type> alias)
- : tag(type_tag::alias), alias(alias)
+ : payload(alias)
{
}
type::type(std::shared_ptr<primitive_type> primitive)
- : tag(type_tag::primitive), primitive(primitive)
+ : payload(primitive)
{
}
type::type(std::shared_ptr<record_type> record)
- : tag(type_tag::record), record(record)
+ : payload(record)
{
}
type::type(std::shared_ptr<pointer_type> pointer)
- : tag(type_tag::pointer), pointer(pointer)
+ : payload(pointer)
{
}
type::type(std::shared_ptr<constant_type> constant)
- : tag(type_tag::constant), constant(constant)
+ : payload(constant)
{
}
type::type(std::shared_ptr<array_type> array)
- : tag(type_tag::array), array(array)
+ : payload(array)
{
}
type::type(std::shared_ptr<procedure_type> procedure)
- : tag(type_tag::procedure), procedure(procedure)
+ : payload(procedure)
{
}
type::type(std::shared_ptr<enumeration_type> enumeration)
- : tag(type_tag::enumeration), enumeration(enumeration)
+ : payload(enumeration)
{
}
- void type::copy(const type& other)
+ template<typename T>
+ std::shared_ptr<T> type::get() const
{
- switch (other.tag)
+ if constexpr (std::is_same_v<T, alias_type>)
{
- case type_tag::empty:
- break;
- case type_tag::alias:
- new (&alias) std::weak_ptr<alias_type>(other.alias);
- break;
- case type_tag::primitive:
- new (&primitive) std::shared_ptr<primitive_type>(other.primitive);
- break;
- case type_tag::record:
- new (&record) std::shared_ptr<record_type>(other.record);
- break;
- case type_tag::pointer:
- new (&pointer) std::shared_ptr<pointer_type>(other.pointer);
- break;
- case type_tag::constant:
- new (&constant) std::shared_ptr<constant_type>(other.constant);
- break;
- case type_tag::array:
- new (&array) std::shared_ptr<array_type>(other.array);
- break;
- case type_tag::procedure:
- new (&procedure) std::shared_ptr<procedure_type>(other.procedure);
- break;
- case type_tag::enumeration:
- new (&enumeration) std::shared_ptr<enumeration_type>(other.enumeration);
- break;
+ if (auto *wp = std::get_if<std::weak_ptr<alias_type>>(&payload))
+ return wp->lock();
+ return nullptr;
}
- }
-
- type::type(const type& other)
- : tag(other.tag)
- {
- copy(other);
- }
-
- void type::move(type&& other)
- {
- switch (other.tag)
- {
- case type_tag::empty:
- break;
- case type_tag::alias:
- new (&alias) std::weak_ptr<alias_type>(std::move(other.alias));
- break;
- case type_tag::primitive:
- new (&primitive) std::shared_ptr<primitive_type>(std::move(other.primitive));
- break;
- case type_tag::record:
- new (&record) std::shared_ptr<record_type>(std::move(other.record));
- break;
- case type_tag::pointer:
- new (&pointer) std::shared_ptr<pointer_type>(std::move(other.pointer));
- break;
- case type_tag::constant:
- new (&constant) std::shared_ptr<constant_type>(std::move(other.constant));
- break;
- case type_tag::array:
- new (&array) std::shared_ptr<array_type>(std::move(other.array));
- break;
- case type_tag::procedure:
- new (&procedure) std::shared_ptr<procedure_type>(std::move(other.procedure));
- break;
- case type_tag::enumeration:
- new (&enumeration) std::shared_ptr<enumeration_type>(std::move(other.enumeration));
- break;
- }
- }
-
- type& type::operator=(const type& other)
- {
- this->~type();
- this->tag = other.tag;
- copy(other);
- return *this;
- }
-
- type::type(type&& other)
- : tag(other.tag)
- {
- move(std::move(other));
- }
-
- type& type::operator=(type&& other)
- {
- this->~type();
- this->tag = other.tag;
- move(std::move(other));
- return *this;
- }
-
- type::~type()
- {
- switch (tag)
+ else
{
- case type_tag::empty:
- break;
- case type_tag::alias:
- this->alias.~weak_ptr<alias_type>();
- break;
- case type_tag::primitive:
- this->primitive.~shared_ptr<primitive_type>();
- break;
- case type_tag::record:
- this->record.~shared_ptr<record_type>();
- break;
- case type_tag::pointer:
- this->pointer.~shared_ptr<pointer_type>();
- break;
- case type_tag::constant:
- this->constant.~shared_ptr<constant_type>();
- break;
- case type_tag::array:
- this->array.~shared_ptr<array_type>();
- break;
- case type_tag::procedure:
- this->procedure.~shared_ptr<procedure_type>();
- break;
- case type_tag::enumeration:
- this->enumeration.~shared_ptr<enumeration_type>();
- break;
+ if (auto *sp = std::get_if<std::shared_ptr<T>>(&payload))
+ return *sp;
+ return nullptr;
}
}
- template<>
- std::shared_ptr<alias_type> type::get<alias_type>() const
- {
- return tag == type_tag::alias ? this->alias.lock() : nullptr;
- }
-
- template<>
- std::shared_ptr<primitive_type> type::get<primitive_type>() const
- {
- return tag == type_tag::primitive ? this->primitive : nullptr;
- }
-
- template<>
- std::shared_ptr<record_type> type::get<record_type>() const
- {
- return tag == type_tag::record ? this->record : nullptr;
- }
-
- template<>
- std::shared_ptr<pointer_type> type::get<pointer_type>() const
- {
- return tag == type_tag::pointer ? this->pointer : nullptr;
- }
-
- template<>
- std::shared_ptr<array_type> type::get<array_type>() const
- {
- return tag == type_tag::array ? this->array : nullptr;
- }
-
- template<>
- std::shared_ptr<constant_type> type::get<constant_type>() const
- {
- return tag == type_tag::constant ? this->constant : nullptr;
- }
-
- template<>
- std::shared_ptr<procedure_type> type::get<procedure_type>() const
- {
- return tag == type_tag::procedure ? this->procedure : nullptr;
- }
-
- template<>
- std::shared_ptr<enumeration_type> type::get<enumeration_type>() const
- {
- return tag == type_tag::enumeration ? this->enumeration : nullptr;
- }
+ // Explicit instantiation for all types used by callers.
+ template std::shared_ptr<alias_type> type::get<alias_type>() const;
+ template std::shared_ptr<primitive_type> type::get<primitive_type>() const;
+ template std::shared_ptr<record_type> type::get<record_type>() const;
+ template std::shared_ptr<pointer_type> type::get<pointer_type>() const;
+ template std::shared_ptr<array_type> type::get<array_type>() const;
+ template std::shared_ptr<constant_type> type::get<constant_type>() const;
+ template std::shared_ptr<procedure_type> type::get<procedure_type>() const;
+ template std::shared_ptr<enumeration_type> type::get<enumeration_type>() const;
bool type::operator==(const std::nullptr_t&) const
{
@@ -293,61 +141,54 @@ namespace elna::boot
bool type::empty() const
{
- return tag == type_tag::empty;
+ return std::holds_alternative<std::monostate>(payload);
}
std::string type::to_string() const
{
- switch (tag)
- {
- case type_tag::empty:
+ return std::visit([](const auto& p) -> std::string {
+ using T = std::decay_t<decltype(p)>;
+ if constexpr (std::is_same_v<T, std::monostate>)
return "<empty>";
- case type_tag::alias:
- return alias.lock()->name;
- case type_tag::primitive:
- 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:
- if (record->base.empty())
- {
+ else if constexpr (std::is_same_v<T, std::weak_ptr<alias_type>>)
+ return p.lock()->name;
+ else if constexpr (std::is_same_v<T, std::shared_ptr<primitive_type>>)
+ return p->identifier;
+ else if constexpr (std::is_same_v<T, std::shared_ptr<pointer_type>>)
+ return "^" + p->base.to_string();
+ else if constexpr (std::is_same_v<T, std::shared_ptr<constant_type>>)
+ return "const " + p->unqualified.to_string();
+ else if constexpr (std::is_same_v<T, std::shared_ptr<array_type>>)
+ return "[" + std::to_string(p->size) + "]" + p->base.to_string();
+ else if constexpr (std::is_same_v<T, std::shared_ptr<record_type>>)
+ {
+ if (p->base.empty())
return "record ... end";
- }
else
+ return "record(" + p->base.to_string() + ") ... end";
+ }
+ else if constexpr (std::is_same_v<T, std::shared_ptr<procedure_type>>)
+ {
+ std::string result = "proc(";
+ for (std::size_t i = 0; i < p->parameters.size(); ++i)
{
- return "record(" + record->base.to_string() + ") ... end";
- }
- case type_tag::procedure:
- {
- std::string result = "proc(";
- for (std::size_t i = 0; i < procedure->parameters.size(); ++i)
- {
- if (i > 0) result += ", ";
- result += procedure->parameters[i].to_string();
- }
- result += ")";
- if (procedure->return_type.no_return)
- {
- result += ": !";
- }
- else if (!procedure->return_type.proper_type.empty())
- {
- result += ": " + procedure->return_type.proper_type.to_string();
- }
- return result;
+ if (i > 0) result += ", ";
+ result += p->parameters[i].to_string();
}
- case type_tag::enumeration:
+ result += ")";
+ if (p->return_type.no_return)
+ result += ": !";
+ else if (!p->return_type.proper_type.empty())
+ result += ": " + p->return_type.proper_type.to_string();
+ return result;
+ }
+ else if constexpr (std::is_same_v<T, std::shared_ptr<enumeration_type>>)
return "(enumeration)";
- }
- __builtin_unreachable();
+ }, payload);
}
alias_type::alias_type(const std::string& name)
- : name(name), reference()
+ : name(name), referent()
{
}
@@ -517,7 +358,7 @@ namespace elna::boot
{
auto unresolved_declaration = this->unresolved.at(symbol_name);
- unresolved_declaration->reference = resolution;
+ unresolved_declaration->referent = resolution;
return unresolved_declaration;
}
@@ -544,7 +385,7 @@ namespace elna::boot
type resolve_underlying_type(std::shared_ptr<alias_type> alias)
{
- return resolve_underlying_type(alias->reference);
+ return resolve_underlying_type(alias->referent);
}
type resolve_underlying_type(const type& alias)
@@ -565,7 +406,7 @@ namespace elna::boot
{
if (auto alias = checked.get<alias_type>())
{
- return resolve_aliases(alias->reference);
+ return resolve_aliases(alias->referent);
}
return checked;
}
diff --git a/boot/type_check.cc b/boot/type_check.cc
index 3667007..b42792b 100644
--- a/boot/type_check.cc
+++ b/boot/type_check.cc
@@ -212,7 +212,8 @@ namespace elna::boot
return true;
}
}
- return !record->base.empty() && contains_constant_member(record->base);
+ return !record->base.empty()
+ && contains_constant_member(resolve_underlying_type(record->base));
}
else if (auto array = referent.get<array_type>())
{
@@ -230,7 +231,7 @@ namespace elna::boot
}
alias_path.push_back(alias->name);
- if (auto another_alias = alias->reference.get<alias_type>())
+ if (auto another_alias = alias->referent.get<alias_type>())
{
return check_unresolved_symbol(another_alias, alias_path);
}
diff --git a/gcc/gcc/elna-builtins.cc b/gcc/gcc/elna-builtins.cc
index 3c424f8..5284563 100644
--- a/gcc/gcc/elna-builtins.cc
+++ b/gcc/gcc/elna-builtins.cc
@@ -178,7 +178,7 @@ namespace elna::gcc
if (looked_up == NULL_TREE)
{
- tree type_tree = get_inner_alias(reference->reference, symbols);
+ tree type_tree = get_inner_alias(reference->referent, symbols);
looked_up = build_decl(UNKNOWN_LOCATION, TYPE_DECL,
get_identifier(symbol_name.c_str()), type_tree);
diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h
index 6884dd7..216021e 100644
--- a/include/elna/boot/symbol.h
+++ b/include/elna/boot/symbol.h
@@ -18,11 +18,12 @@ along with GCC; see the file COPYING3. If not see
#pragma once
#include <cstdint>
-#include <unordered_map>
-#include <string>
+#include <forward_list>
#include <memory>
+#include <string>
+#include <unordered_map>
+#include <variant>
#include <vector>
-#include <forward_list>
#include "elna/boot/result.h"
@@ -39,36 +40,21 @@ namespace elna::boot
class type
{
- enum class type_tag
- {
- empty,
- alias,
- primitive,
- record,
- pointer,
- constant,
- array,
- procedure,
- enumeration
- };
- type_tag tag{ type_tag::empty };
- union
- {
- std::weak_ptr<alias_type> alias;
- std::shared_ptr<primitive_type> primitive;
- std::shared_ptr<record_type> record;
- std::shared_ptr<pointer_type> pointer;
- std::shared_ptr<constant_type> constant;
- std::shared_ptr<array_type> array;
- std::shared_ptr<procedure_type> procedure;
- std::shared_ptr<enumeration_type> enumeration;
- };
-
- void copy(const type& other);
- void move(type&& other);
+ std::variant<
+ std::monostate,
+ std::weak_ptr<alias_type>,
+ std::shared_ptr<primitive_type>,
+ std::shared_ptr<record_type>,
+ std::shared_ptr<pointer_type>,
+ std::shared_ptr<constant_type>,
+ std::shared_ptr<array_type>,
+ std::shared_ptr<procedure_type>,
+ std::shared_ptr<enumeration_type>
+ > payload;
public:
- type();
+ type() = default;
+
explicit type(std::shared_ptr<alias_type> alias);
explicit type(std::shared_ptr<primitive_type> primitive);
explicit type(std::shared_ptr<record_type> record);
@@ -78,14 +64,6 @@ namespace elna::boot
explicit type(std::shared_ptr<procedure_type> procedure);
explicit type(std::shared_ptr<enumeration_type> enumeration);
- type(const type& other);
- type& operator=(const type& other);
-
- type(type&& other);
- type& operator=(type&& other);
-
- ~type();
-
template<typename T>
std::shared_ptr<T> get() const;
@@ -104,7 +82,7 @@ namespace elna::boot
struct alias_type
{
const std::string name;
- type reference;
+ type referent;
explicit alias_type(const std::string& name);
};
diff --git a/testsuite/compilable/record_const_base.elna b/testsuite/compilable/record_const_base.elna
new file mode 100644
index 0000000..f24d27b
--- /dev/null
+++ b/testsuite/compilable/record_const_base.elna
@@ -0,0 +1,18 @@
+type
+ B = record
+ x: Int
+ end
+ CB = const B
+ D = record(CB)
+ y: Int
+ end
+
+proc f()
+var
+ d: D
+begin
+ d.x := 1;
+ d.y := 2
+return
+
+end.