From 7559df5896c552bd34d04dd3a5e240f24131eb6c Mon Sep 17 00:00:00 2001
From: Eugen Wissner <belka@caraus.de>
Date: Thu, 6 Mar 2025 22:59:41 +0100
Subject: [PATCH] Unify the build_type function

---
 boot/ast.cc                     |  6 ++-
 boot/parser.yy                  |  2 +-
 boot/semantic.cc                | 61 ++++++++++++++++++++++
 gcc/elna-generic.cc             | 89 ++++-----------------------------
 gcc/elna1.cc                    | 11 +++-
 include/elna/boot/ast.h         | 11 ++--
 include/elna/boot/semantic.h    | 28 ++++++++++-
 include/elna/gcc/elna-generic.h | 18 +------
 8 files changed, 116 insertions(+), 110 deletions(-)

diff --git a/boot/ast.cc b/boot/ast.cc
index 20b755c..d3e0b9f 100644
--- a/boot/ast.cc
+++ b/boot/ast.cc
@@ -464,7 +464,8 @@ namespace boot
         return *m_base;
     }
 
-    record_type_expression::record_type_expression(const struct position position, fields_t&& fields)
+    record_type_expression::record_type_expression(const struct position position,
+            std::vector<field_declaration>&& fields)
         : type_expression(position), fields(std::move(fields))
     {
     }
@@ -479,7 +480,8 @@ namespace boot
         return std::static_pointer_cast<record_type_expression>(shared_from_this());
     }
 
-    union_type_expression::union_type_expression(const struct position position, fields_t&& fields)
+    union_type_expression::union_type_expression(const struct position position,
+            std::vector<field_declaration>&& fields)
         : type_expression(position), fields(std::move(fields))
     {
     }
diff --git a/boot/parser.yy b/boot/parser.yy
index 13f9fe7..e5ed856 100644
--- a/boot/parser.yy
+++ b/boot/parser.yy
@@ -145,7 +145,7 @@ along with GCC; see the file COPYING3.  If not see
 %type <elna::boot::type_definition *> type_definition;
 %type <std::vector<elna::boot::type_definition *>> type_definitions type_part;
 %type <elna::boot::block *> block;
-%type <elna::boot::field_t> field_declaration;
+%type <elna::boot::field_declaration> field_declaration;
 %type <std::vector<std::pair<std::string, std::shared_ptr<elna::boot::type_expression>>>>
     optional_fields required_fields;
 %type <std::vector<elna::boot::conditional_statements *>> elsif_then_statements elsif_do_statements;
diff --git a/boot/semantic.cc b/boot/semantic.cc
index 6735976..ae1157d 100644
--- a/boot/semantic.cc
+++ b/boot/semantic.cc
@@ -69,5 +69,66 @@ namespace boot
     {
         return this;
     }
+
+    void declaration_visitor::visit(program *program)
+    {
+        for (type_definition *const type : program->types)
+        {
+            this->unresolved.insert({ type->identifier, new alias_type() });
+        }
+        for (type_definition *const type : program->types)
+        {
+            type->accept(this);
+        }
+    }
+
+    void declaration_visitor::visit(type_definition *definition)
+    {
+        auto unresolved_declaration = this->unresolved.at(definition->identifier);
+
+        definition->body().accept(this);
+
+        if (this->current_type != nullptr)
+        {
+            unresolved_declaration->reference = this->current_type;
+        }
+        this->current_type = nullptr;
+    }
+
+    void declaration_visitor::visit(primitive_type_expression *type)
+    {
+        auto unresolved_alias = this->unresolved.find(type->name);
+
+        if (unresolved_alias != this->unresolved.end())
+        {
+            this->current_type = unresolved_alias->second;
+        }
+        else
+        {
+            this->current_type = new primitive_type(type->name);
+        }
+    }
+
+    void declaration_visitor::visit(array_type_expression *type)
+    {
+    }
+
+    void declaration_visitor::visit(pointer_type_expression *type)
+    {
+    }
+
+    void declaration_visitor::visit(record_type_expression *type)
+    {
+        this->current_type = new record_type();
+    }
+
+    void declaration_visitor::visit(union_type_expression *type)
+    {
+        this->current_type = new union_type();
+    }
+
+    void declaration_visitor::visit(procedure_type_expression *type)
+    {
+    }
 }
 }
diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc
index 3ee4f94..33af896 100644
--- a/gcc/elna-generic.cc
+++ b/gcc/elna-generic.cc
@@ -38,19 +38,7 @@ namespace elna
 {
 namespace gcc
 {
-    declaration_visitor::declaration_visitor(std::shared_ptr<symbol_table> symbol_table)
-        : symbols(symbol_table)
-    {
-        this->symbols->enter("Int", elna_int_type_node);
-        this->symbols->enter("Word", elna_word_type_node);
-        this->symbols->enter("Char", elna_char_type_node);
-        this->symbols->enter("Bool", elna_bool_type_node);
-        this->symbols->enter("Byte", elna_byte_type_node);
-        this->symbols->enter("Float", elna_float_type_node);
-        this->symbols->enter("String", elna_string_type_node);
-    }
-
-    tree declaration_visitor::get_inner_alias(const boot::alias_type& t)
+    static tree get_inner_alias(std::shared_ptr<symbol_table> symbol_table, const boot::alias_type& t)
     {
         if (t.reference == nullptr)
         {
@@ -58,11 +46,11 @@ namespace gcc
         }
         else if (auto reference = t.reference->is_primitive())
         {
-            return this->symbols->lookup(reference->identifier);
+            return symbol_table->lookup(reference->identifier);
         }
         else if (auto reference = t.reference->is_alias())
         {
-            return get_inner_alias(*reference);
+            return get_inner_alias(symbol_table, *reference);
         }
         else if (auto reference = t.reference->is_record())
         {
@@ -75,75 +63,16 @@ namespace gcc
         return NULL_TREE;
     }
 
-    boot::type *declaration_visitor::build_type(boot::type_expression *type_expression)
+    void do_semantic_analysis(std::shared_ptr<symbol_table> symbols, std::unique_ptr<boot::program>& ast)
     {
-        if (auto alias_node = type_expression->is_primitive())
-        {
-            return this->unresolved.at(alias_node->name);
-        }
-        else if (auto alias_node = type_expression->is_record())
-        {
-            return build_record(alias_node.get());
-        }
-        else if (auto alias_node = type_expression->is_union())
-        {
-            return build_union(alias_node.get());
-        }
-        return nullptr;
-    }
+        boot::declaration_visitor declaration_visitor;
 
-    boot::record_type *declaration_visitor::build_record(boot::record_type_expression *type_expression)
-    {
-        return new boot::record_type();
-    }
-
-    boot::union_type *declaration_visitor::build_union(boot::union_type_expression *type_expression)
-    {
-        return new boot::union_type();
-    }
-
-    void declaration_visitor::visit(boot::program *program)
-    {
-        for (boot::type_definition *const type : program->types)
+        declaration_visitor.visit(ast.get());
+        for (auto unresolved : declaration_visitor.unresolved)
         {
-            type->accept(this);
+            auto inner_alias = elna::gcc::get_inner_alias(symbols, *unresolved.second);
+            symbols->enter(unresolved.first, inner_alias);
         }
-        for (boot::type_definition *const type : program->types)
-        {
-            auto unresolved_declaration = this->unresolved.at(type->identifier);
-
-            if (auto alias_node = type->body().is_primitive())
-            {
-                auto unresolved_alias = this->unresolved.find(alias_node->name);
-
-                if (unresolved_alias != this->unresolved.end())
-                {
-                    unresolved_declaration->reference = unresolved_alias->second;
-                }
-                else
-                {
-                    unresolved_declaration->reference = new boot::primitive_type(alias_node->name);
-                }
-            }
-            else if (auto alias_node = type->body().is_record())
-            {
-                unresolved_declaration->reference = build_record(alias_node.get());
-            }
-            else if (auto alias_node = type->body().is_union())
-            {
-                unresolved_declaration->reference = build_union(alias_node.get());
-            }
-        }
-        for (auto unresolved : this->unresolved)
-        {
-            auto inner_alias = get_inner_alias(*unresolved.second);
-            this->symbols->enter(unresolved.first, inner_alias);
-        }
-    }
-
-    void declaration_visitor::visit(boot::type_definition *definition)
-    {
-        this->unresolved.insert({ definition->identifier, new boot::alias_type() });
     }
 
     generic_visitor::generic_visitor(std::shared_ptr<symbol_table> symbol_table)
diff --git a/gcc/elna1.cc b/gcc/elna1.cc
index 5713719..07d8a31 100644
--- a/gcc/elna1.cc
+++ b/gcc/elna1.cc
@@ -90,10 +90,17 @@ static void elna_parse_file(const char *filename)
     {
         std::shared_ptr<elna::gcc::symbol_table> symbol_table = std::make_shared<elna::gcc::symbol_table>();
 
-        elna::gcc::declaration_visitor declaration_visitor{ symbol_table };
+        symbol_table->enter("Int", elna_int_type_node);
+        symbol_table->enter("Word", elna_word_type_node);
+        symbol_table->enter("Char", elna_char_type_node);
+        symbol_table->enter("Bool", elna_bool_type_node);
+        symbol_table->enter("Byte", elna_byte_type_node);
+        symbol_table->enter("Float", elna_float_type_node);
+        symbol_table->enter("String", elna_string_type_node);
+
+        elna::gcc::do_semantic_analysis(symbol_table, driver.tree);
         elna::gcc::generic_visitor generic_visitor{ symbol_table };
 
-        declaration_visitor.visit(driver.tree.get());
         generic_visitor.visit(driver.tree.get());
     }
     linemap_add(line_table, LC_LEAVE, 0, NULL, 0);
diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h
index 0727a39..6c32a54 100644
--- a/include/elna/boot/ast.h
+++ b/include/elna/boot/ast.h
@@ -294,15 +294,14 @@ namespace boot
         type_expression& base();
     };
 
-    using field_t = std::pair<std::string, std::shared_ptr<type_expression>>;
-    using fields_t = std::vector<field_t>;
+    using field_declaration = std::pair<std::string, std::shared_ptr<type_expression>>;
 
     class record_type_expression : public type_expression
     {
     public:
-        fields_t fields;
+        const std::vector<field_declaration> fields;
 
-        record_type_expression(const struct position position, fields_t&& fields);
+        record_type_expression(const struct position position, std::vector<field_declaration>&& fields);
 
         void accept(parser_visitor *visitor);
         std::shared_ptr<record_type_expression> is_record() override;
@@ -311,9 +310,9 @@ namespace boot
     class union_type_expression : public type_expression
     {
     public:
-        fields_t fields;
+        std::vector<field_declaration> fields;
 
-        union_type_expression(const struct position position, fields_t&& fields);
+        union_type_expression(const struct position position, std::vector<field_declaration>&& fields);
 
         void accept(parser_visitor *visitor);
         std::shared_ptr<union_type_expression> is_union() override;
diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h
index de6030a..a078f98 100644
--- a/include/elna/boot/semantic.h
+++ b/include/elna/boot/semantic.h
@@ -17,6 +17,9 @@ along with GCC; see the file COPYING3.  If not see
 
 #include <string>
 #include <vector>
+#include <unordered_map>
+
+#include "elna/boot/ast.h"
 
 namespace elna
 {
@@ -56,10 +59,12 @@ namespace boot
         primitive_type *is_primitive() override;
     };
 
+    using type_field = typename std::pair<std::string, type *>;
+
     class record_type : public type
     {
     public:
-        std::vector<std::pair<std::string, type *>> fields;
+        std::vector<type_field> fields;
 
         record_type *is_record() override;
     };
@@ -67,9 +72,28 @@ namespace boot
     class union_type : public type
     {
     public:
-        std::vector<std::pair<std::string, type *>> fields;
+        std::vector<type_field> fields;
 
         union_type *is_union() override;
     };
+
+    class declaration_visitor final : public empty_visitor
+    {
+        type *current_type{ nullptr };
+
+    public:
+        std::unordered_map<std::string, alias_type *> unresolved;
+
+        declaration_visitor() = default;
+
+        void visit(primitive_type_expression *type) override;
+        void visit(array_type_expression *type) override;
+        void visit(pointer_type_expression *type) override;
+        void visit(program *program) override;
+        void visit(type_definition *definition) override;
+        void visit(record_type_expression *type) override;
+        void visit(union_type_expression *type) override;
+        void visit(procedure_type_expression *type) override;
+    };
 }
 }
diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h
index 4f4c635..2dfb2d9 100644
--- a/include/elna/gcc/elna-generic.h
+++ b/include/elna/gcc/elna-generic.h
@@ -28,29 +28,13 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "tree-iterator.h"
 
-#include <unordered_map>
 #include <string>
 
 namespace elna
 {
 namespace gcc
 {
-    class declaration_visitor final : public boot::empty_visitor
-    {
-        std::shared_ptr<symbol_table> symbols;
-        std::unordered_map<std::string, boot::alias_type *> unresolved;
-
-        boot::type *build_type(boot::type_expression *type_expression);
-        boot::record_type *build_record(boot::record_type_expression *type_expression);
-        boot::union_type *build_union(boot::union_type_expression *type_expression);
-        tree get_inner_alias(const boot::alias_type& t);
-
-    public:
-        declaration_visitor(std::shared_ptr<symbol_table> symbol_table);
-
-        void visit(boot::program *program) override;
-        void visit(boot::type_definition *definition) override;
-    };
+    void do_semantic_analysis(std::shared_ptr<symbol_table> symbols, std::unique_ptr<boot::program>& ast);
 
     class generic_visitor final : public boot::empty_visitor
     {