From 868db6e0bffa9276976189ca6f9c2960f62d0e6c Mon Sep 17 00:00:00 2001
From: Eugen Wissner <belka@caraus.de>
Date: Sat, 8 Mar 2025 13:55:42 +0100
Subject: [PATCH] Add array_type

---
 boot/semantic.cc             | 185 ++++++++++++++++++++++++++++++-----
 include/elna/boot/semantic.h |  54 +++++++---
 2 files changed, 198 insertions(+), 41 deletions(-)

diff --git a/boot/semantic.cc b/boot/semantic.cc
index 9489625..8c6482d 100644
--- a/boot/semantic.cc
+++ b/boot/semantic.cc
@@ -21,37 +21,154 @@ namespace elna
 {
 namespace boot
 {
-    type::type(alias_type *alias)
-        : payload({ .alias = alias }), tag(type_tag::alias)
+    type::type()
+        : tag(type_tag::alias)
     {
     }
 
-    type::type(primitive_type *primitive)
-        : payload({ .primitive = primitive }), tag(type_tag::primitive)
+    type::type(std::shared_ptr<alias_type> alias)
+        : tag(type_tag::alias), alias(alias)
     {
     }
 
-    type::type(record_type *record)
-        : payload({ .record = record }), tag(type_tag::record)
+    type::type(std::shared_ptr<primitive_type> primitive)
+        : tag(type_tag::primitive), primitive(primitive)
     {
     }
 
-    type::type(union_type *_union)
-        : payload({ ._union = _union }), tag(type_tag::_union)
+    type::type(std::shared_ptr<record_type> record)
+        : tag(type_tag::record), record(record)
     {
     }
 
-    type::type(pointer_type *pointer)
-        : payload({ .pointer = pointer }), tag(type_tag::pointer)
+    type::type(std::shared_ptr<union_type> _union)
+        : tag(type_tag::_union), _union(_union)
     {
     }
 
+    type::type(std::shared_ptr<pointer_type> pointer)
+        : tag(type_tag::pointer), pointer(pointer)
+    {
+    }
+
+    type::type(std::shared_ptr<array_type> array)
+        : tag(type_tag::array), array(array)
+    {
+    }
+
+    void type::copy(const type& other)
+    {
+        switch (other.tag)
+        {
+        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::weak_ptr<primitive_type>(other.primitive);
+            break;
+        case type_tag::record:
+            new (&record) std::shared_ptr<record_type>(other.record);
+            break;
+        case type_tag::_union:
+            new (&_union) std::shared_ptr<union_type>(other._union);
+            break;
+        case type_tag::pointer:
+            new (&pointer) std::shared_ptr<pointer_type>(other.pointer);
+            break;
+        case type_tag::array:
+            new (&array) std::shared_ptr<array_type>(other.array);
+            break;
+        }
+    }
+
+    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::weak_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::_union:
+            new (&_union) std::shared_ptr<union_type>(std::move(other._union));
+            break;
+        case type_tag::pointer:
+            new (&pointer) std::shared_ptr<pointer_type>(std::move(other.pointer));
+            break;
+        case type_tag::array:
+            new (&array) std::shared_ptr<array_type>(std::move(other.array));
+            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)
+        {
+        case type_tag::empty:
+            break;
+        case type_tag::alias:
+            break;
+        case type_tag::primitive:
+            break;
+        case type_tag::record:
+            this->record.~shared_ptr<record_type>();
+            break;
+        case type_tag::_union:
+            this->_union.~shared_ptr<union_type>();
+            break;
+        case type_tag::pointer:
+            this->pointer.~shared_ptr<pointer_type>();
+            break;
+        case type_tag::array:
+            this->array.~shared_ptr<array_type>();
+            break;
+        }
+    }
+
     template<>
-    alias_type *const type::get<alias_type>() const
+    std::shared_ptr<alias_type> type::get<alias_type>() const
     {
         if (tag == type_tag::alias)
         {
-            return payload.alias;
+            return this->alias.lock();
         }
         else
         {
@@ -60,11 +177,11 @@ namespace boot
     }
 
     template<>
-    primitive_type *const type::get<primitive_type>() const
+    std::shared_ptr<primitive_type> type::get<primitive_type>() const
     {
         if (tag == type_tag::primitive)
         {
-            return payload.primitive;
+            return this->primitive.lock();
         }
         else
         {
@@ -73,11 +190,11 @@ namespace boot
     }
 
     template<>
-    record_type *const type::get<record_type>() const
+    std::shared_ptr<record_type> type::get<record_type>() const
     {
         if (tag == type_tag::record)
         {
-            return payload.record;
+            return this->record;
         }
         else
         {
@@ -86,11 +203,11 @@ namespace boot
     }
 
     template<>
-    union_type *const type::get<union_type>() const
+    std::shared_ptr<union_type> type::get<union_type>() const
     {
         if (tag == type_tag::_union)
         {
-            return payload._union;
+            return this->_union;
         }
         else
         {
@@ -99,11 +216,24 @@ namespace boot
     }
 
     template<>
-    pointer_type *const type::get<pointer_type>() const
+    std::shared_ptr<pointer_type> type::get<pointer_type>() const
     {
         if (tag == type_tag::pointer)
         {
-            return payload.pointer;
+            return this->pointer;
+        }
+        else
+        {
+            return nullptr;
+        }
+    }
+
+    template<>
+    std::shared_ptr<array_type> type::get<array_type>() const
+    {
+        if (tag == type_tag::array)
+        {
+            return this->array;
         }
         else
         {
@@ -121,6 +251,11 @@ namespace boot
     {
     }
 
+    array_type::array_type(type base, std::uint64_t size)
+        : base(base), size(size)
+    {
+    }
+
     primitive_type::primitive_type(const std::string& identifier)
         : identifier(identifier)
     {
@@ -130,7 +265,7 @@ namespace boot
     {
         for (type_definition *const type : program->types)
         {
-            this->unresolved.insert({ type->identifier, new alias_type() });
+            this->unresolved.insert({ type->identifier, std::make_shared<alias_type>() });
         }
         for (type_definition *const type : program->types)
         {
@@ -157,7 +292,7 @@ namespace boot
         }
         else
         {
-            this->current_type = type(new primitive_type(type_expression->name));
+            this->current_type = type(std::make_shared<primitive_type>(type_expression->name));
         }
     }
 
@@ -168,19 +303,19 @@ namespace boot
     void declaration_visitor::visit(pointer_type_expression *type_expression)
     {
         type_expression->base().accept(this);
-        this->current_type = type(new pointer_type(this->current_type));
+        this->current_type = type(std::make_shared<pointer_type>(this->current_type));
     }
 
     void declaration_visitor::visit(record_type_expression *type_expression)
     {
-        auto type_definition = new record_type();
+        auto type_definition = std::make_shared<record_type>();
 
         this->current_type = type(type_definition);
     }
 
     void declaration_visitor::visit(union_type_expression *type_expression)
     {
-        auto type_definition = new union_type();
+        auto type_definition = std::make_shared<union_type>();
 
         this->current_type = type(type_definition);
     }
diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h
index fc343b2..e7915ff 100644
--- a/include/elna/boot/semantic.h
+++ b/include/elna/boot/semantic.h
@@ -18,6 +18,7 @@ along with GCC; see the file COPYING3.  If not see
 #include <string>
 #include <vector>
 #include <unordered_map>
+#include <memory>
 
 #include "elna/boot/ast.h"
 
@@ -30,6 +31,7 @@ namespace boot
     class record_type;
     class union_type;
     class pointer_type;
+    class array_type;
 
     class type
     {
@@ -41,29 +43,41 @@ namespace boot
             record,
             _union,
             pointer,
+            array
         };
+        type_tag tag{ type_tag::empty };
         union
         {
-            nullptr_t empty;
-            alias_type *alias;
-            primitive_type *primitive;
-            record_type *record;
-            union_type *_union;
-            pointer_type *pointer;
-        } payload{ .empty = nullptr };
+            std::weak_ptr<alias_type> alias;
+            std::weak_ptr<primitive_type> primitive;
+            std::shared_ptr<record_type> record;
+            std::shared_ptr<union_type> _union;
+            std::shared_ptr<pointer_type> pointer;
+            std::shared_ptr<array_type> array;
+        };
 
-        type_tag tag{ type_tag::empty };
+        void copy(const type& other);
+        void move(type&& other);
 
     public:
-        type() = default;
-        explicit type(alias_type *alias);
-        explicit type(primitive_type *primitive);
-        explicit type(record_type *record);
-        explicit type(union_type *_union);
-        explicit type(pointer_type *pointer);
+        type();
+        explicit type(std::shared_ptr<alias_type> alias);
+        explicit type(std::shared_ptr<primitive_type> primitive);
+        explicit type(std::shared_ptr<record_type> record);
+        explicit type(std::shared_ptr<union_type> _union);
+        explicit type(std::shared_ptr<pointer_type> pointer);
+        explicit type(std::shared_ptr<array_type> array);
+
+        type(const type& other);
+        type& operator=(const type& other);
+
+        type(type&& other);
+        type& operator=(type&& other);
+
+        ~type();
 
         template<typename T>
-        T *const get() const;
+        std::shared_ptr<T> get() const;
 
         bool empty() const;
     };
@@ -80,6 +94,14 @@ namespace boot
         explicit pointer_type(type base);
     };
 
+    struct array_type
+    {
+        const type base;
+        const std::uint64_t size;
+
+        array_type(type base, std::uint64_t size);
+    };
+
     struct primitive_type
     {
         const std::string identifier;
@@ -104,7 +126,7 @@ namespace boot
         type current_type;
 
     public:
-        std::unordered_map<std::string, alias_type *> unresolved;
+        std::unordered_map<std::string, std::shared_ptr<alias_type>> unresolved;
 
         declaration_visitor() = default;