From 8dc02047dfa2aa87f71c21c6a6a2f4ea5b88df95 Mon Sep 17 00:00:00 2001
From: Eugen Wissner <belka@caraus.de>
Date: Tue, 4 Mar 2025 22:56:32 +0100
Subject: [PATCH] Add second GENERIC visitor

---
 Rakefile                        | 104 -----------
 boot/ast.cc                     | 300 +++++++++++++++++++++++++++++++-
 boot/semantic.cc                |  33 ----
 boot/symbol.cc                  |  37 ----
 gcc/Make-lang.in                |   2 -
 gcc/elna-generic.cc             | 137 ++++++++-------
 gcc/elna1.cc                    |   7 +-
 include/elna/boot/ast.h         | 199 +++++++++++++++++----
 include/elna/boot/semantic.h    |  37 ----
 include/elna/boot/symbol.h      |  28 ---
 include/elna/gcc/elna-generic.h |  26 ++-
 tools/support.rb                |   3 -
 12 files changed, 572 insertions(+), 341 deletions(-)
 delete mode 100644 boot/semantic.cc
 delete mode 100644 boot/symbol.cc
 delete mode 100644 include/elna/boot/semantic.h

diff --git a/Rakefile b/Rakefile
index aae04fe..5d04bd5 100644
--- a/Rakefile
+++ b/Rakefile
@@ -76,107 +76,3 @@ file (TMP + 'elna').to_path => ['source.elna']
 file (TMP + 'elna').to_path => [(HOST_INSTALL + 'bin/gelna').to_path] do |task|
   sh (HOST_INSTALL + 'bin/gelna').to_path, '-o', task.name, task.prerequisites.first
 end
-
-namespace :cross do
-  desc 'Build cross toolchain'
-  task :init, [:target] do |_, args|
-    args.with_defaults target: 'riscv32-unknown-linux-gnu'
-
-    options = find_build_target GCC_VERSION, args[:target]
-    env = {
-      'PATH' => "#{options.rootfs.realpath + 'bin'}:#{ENV['PATH']}"
-    }
-    sh env, 'riscv32-unknown-linux-gnu-gcc',
-      '-ffreestanding', '-static',
-      '-o', (options.tools + 'init').to_path,
-      'tools/init.c'
-  end
-end
-
-namespace :test do
-  test_sources = FileList['tests/vm/*.elna', 'tests/vm/*.s']
-  compiler = TMP + 'bin/elna'
-  object_directory = TMP + 'riscv/tests'
-  root_directory = TMP + 'riscv/root'
-  executable_directory = root_directory + 'tests'
-  expectation_directory = root_directory + 'expectations'
-  init = TMP + 'riscv/root/init'
-  builtin = TMP + 'riscv/builtin.o'
-
-  directory root_directory
-  directory object_directory
-  directory executable_directory
-  directory expectation_directory
-
-  file builtin => ['tools/builtin.s', object_directory] do |task|
-    sh AS, '-o', task.name, task.prerequisites.first
-  end
-
-  test_files = test_sources.flat_map do |test_source|
-    test_basename = File.basename(test_source, '.*')
-    test_object = object_directory + test_basename.ext('.o')
-
-    file test_object => [test_source, object_directory] do |task|
-      case File.extname(task.prerequisites.first)
-      when '.s'
-        sh AS, '-mno-relax', '-o', task.name, task.prerequisites.first
-      when '.elna'
-        sh compiler, '--output', task.name, task.prerequisites.first
-      else
-        raise "Unknown source file extension #{task.prerequisites.first}"
-      end
-    end
-    test_executable = executable_directory + test_basename
-
-    file test_executable => [test_object, executable_directory, builtin] do |task|
-      objects = task.prerequisites.filter { |prerequisite| File.file? prerequisite }
-
-      sh LINKER, '-o', test_executable.to_path, *objects
-    end
-    expectation_name = test_basename.ext '.txt'
-    source_expectation = "tests/expectations/#{expectation_name}"
-    target_expectation = expectation_directory + expectation_name
-
-    file target_expectation => [source_expectation, expectation_directory] do
-      cp source_expectation, target_expectation
-    end
-
-    [test_executable, target_expectation]
-  end
-
-  file init => [root_directory] do |task|
-    cp (TMP + 'tools/init'), task.name
-  end
-  # Directories should come first.
-  test_files.unshift executable_directory, expectation_directory, init
-
-  file (TMP + 'riscv/root.cpio') => test_files do |task|
-    root_files = task.prerequisites
-      .map { |prerequisite| Pathname.new(prerequisite).relative_path_from(root_directory).to_path }
-
-    File.open task.name, 'wb' do |cpio_file|
-      cpio_options = {
-        chdir: root_directory.to_path
-      }
-      cpio_stream = Open3.popen2 'cpio', '-o', '--format=newc', cpio_options do |stdin, stdout, wait_thread|
-        stdin.write root_files.join("\n")
-        stdin.close
-        stdout.each { |chunk| cpio_file.write chunk }
-        wait_thread.value
-      end
-    end
-  end
-
-  task :vm => (TMP + 'riscv/root.cpio') do |task|
-    kernels = FileList.glob(TMP + 'tools/linux-*/arch/riscv/boot/Image')
-
-    sh 'qemu-system-riscv32',
-      '-nographic',
-      '-M', 'virt',
-      '-bios', 'default',
-      '-kernel', kernels.first,
-      '-append', 'quiet panic=1',
-      '-initrd', task.prerequisites.first,
-      '-no-reboot'
-  end
-end
diff --git a/boot/ast.cc b/boot/ast.cc
index 50253df..20b755c 100644
--- a/boot/ast.cc
+++ b/boot/ast.cc
@@ -191,6 +191,10 @@ namespace boot
     {
     }
 
+    node::~node()
+    {
+    }
+
     const struct position& node::position() const
     {
         return this->source_position;
@@ -200,10 +204,145 @@ namespace boot
     {
     }
 
+    statement::~statement()
+    {
+    }
+
+    assign_statement *statement::is_assign()
+    {
+        return nullptr;
+    }
+
+    if_statement *statement::is_if()
+    {
+        return nullptr;
+    }
+
+    while_statement *statement::is_while()
+    {
+        return nullptr;
+    }
+
+    return_statement *statement::is_return()
+    {
+        return nullptr;
+    }
+
+    defer_statement *statement::is_defer()
+    {
+        return nullptr;
+    }
+
+    procedure_call *statement::is_call_statement()
+    {
+        return nullptr;
+    }
+
+    void statement::accept(parser_visitor *visitor)
+    {
+        if (assign_statement *node = is_assign())
+        {
+            return node->accept(visitor);
+        }
+        else if (if_statement *node = is_if())
+        {
+            return node->accept(visitor);
+        }
+        else if (while_statement *node = is_while())
+        {
+            return node->accept(visitor);
+        }
+        else if (return_statement *node = is_return())
+        {
+            return node->accept(visitor);
+        }
+        else if (defer_statement *node = is_defer())
+        {
+            return node->accept(visitor);
+        }
+        else if (procedure_call *node = is_call_statement())
+        {
+            return node->accept(visitor);
+        }
+        __builtin_unreachable();
+    }
+
     expression::expression()
     {
     }
 
+    expression::~expression()
+    {
+    }
+
+    cast_expression *expression::is_cast()
+    {
+        return nullptr;
+    }
+
+    traits_expression *expression::is_traits()
+    {
+        return nullptr;
+    }
+
+    binary_expression *expression::is_binary()
+    {
+        return nullptr;
+    }
+
+    unary_expression *expression::is_unary()
+    {
+        return nullptr;
+    }
+
+    designator_expression *expression::is_designator()
+    {
+        return nullptr;
+    }
+
+    procedure_call *expression::is_call_expression()
+    {
+        return nullptr;
+    }
+
+    literal *expression::is_literal()
+    {
+        return nullptr;
+    }
+
+    void expression::accept(parser_visitor *visitor)
+    {
+        if (cast_expression *node = is_cast())
+        {
+            return node->accept(visitor);
+        }
+        else if (traits_expression *node = is_traits())
+        {
+            return node->accept(visitor);
+        }
+        else if (binary_expression *node = is_binary())
+        {
+            return node->accept(visitor);
+        }
+        else if (unary_expression *node = is_unary())
+        {
+            return node->accept(visitor);
+        }
+        else if (designator_expression *node = is_designator())
+        {
+            return node->accept(visitor);
+        }
+        else if (procedure_call *node = is_call_expression())
+        {
+            return node->accept(visitor);
+        }
+        else if (literal *node = is_literal())
+        {
+            return node->accept(visitor);
+        }
+        __builtin_unreachable();
+    }
+
     type_expression::type_expression(const struct position position)
         : node(position)
     {
@@ -239,6 +378,35 @@ namespace boot
         return nullptr;
     }
 
+    void type_expression::accept(parser_visitor *visitor)
+    {
+        if (std::shared_ptr<primitive_type_expression> node = is_primitive())
+        {
+            return node->accept(visitor);
+        }
+        else if (std::shared_ptr<array_type_expression> node = is_array())
+        {
+            return node->accept(visitor);
+        }
+        else if (std::shared_ptr<pointer_type_expression> node = is_pointer())
+        {
+            return node->accept(visitor);
+        }
+        else if (std::shared_ptr<record_type_expression> node = is_record())
+        {
+            return node->accept(visitor);
+        }
+        else if (std::shared_ptr<union_type_expression> node = is_union())
+        {
+            return node->accept(visitor);
+        }
+        else if (std::shared_ptr<procedure_type_expression> node = is_procedure())
+        {
+            return node->accept(visitor);
+        }
+        __builtin_unreachable();
+    }
+
     primitive_type_expression::primitive_type_expression(const struct position position, const std::string& name)
         : type_expression(position), name(name)
     {
@@ -486,6 +654,47 @@ namespace boot
     {
     }
 
+    literal *literal::is_literal()
+    {
+        return this;
+    }
+
+    void literal::accept(parser_visitor *visitor)
+    {
+        if (number_literal<std::int32_t> *node = is_int())
+        {
+            return node->accept(visitor);
+        }
+        else if (number_literal<std::uint32_t> *node = is_word())
+        {
+            return node->accept(visitor);
+        }
+        else if (number_literal<double> *node = is_float())
+        {
+            return node->accept(visitor);
+        }
+        else if (number_literal<bool> *node = is_bool())
+        {
+            return node->accept(visitor);
+        }
+        else if (number_literal<unsigned char> *node = is_char())
+        {
+            return node->accept(visitor);
+        }
+        else if (number_literal<std::nullptr_t> *node = is_nil())
+        {
+            return node->accept(visitor);
+        }
+        else if (number_literal<std::string> *node = is_string())
+        {
+            return node->accept(visitor);
+        }
+        else
+        {
+            __builtin_unreachable();
+        }
+    }
+
     defer_statement::defer_statement(const struct position position)
         : node(position)
     {
@@ -496,6 +705,11 @@ namespace boot
         visitor->visit(this);
     }
 
+    defer_statement *defer_statement::is_defer()
+    {
+        return this;
+    }
+
     defer_statement::~defer_statement()
     {
         for (statement *body_statement : statements)
@@ -508,6 +722,36 @@ namespace boot
     {
     }
 
+    designator_expression::~designator_expression()
+    {
+    }
+
+    designator_expression *designator_expression::is_designator()
+    {
+        return this;
+    }
+
+    void designator_expression::accept(parser_visitor *visitor)
+    {
+        if (variable_expression *node = is_variable())
+        {
+            return visitor->visit(node);
+        }
+        else if (array_access_expression *node = is_array_access())
+        {
+            return visitor->visit(node);
+        }
+        else if (field_access_expression *node = is_field_access())
+        {
+            return visitor->visit(node);
+        }
+        else if (dereference_expression *node = is_dereference())
+        {
+            return visitor->visit(node);
+        }
+        __builtin_unreachable();
+    }
+
     variable_expression::variable_expression(const struct position position, const std::string& name)
         : node(position), name(name)
     {
@@ -623,6 +867,11 @@ namespace boot
         visitor->visit(this);
     }
 
+    binary_expression *binary_expression::is_binary()
+    {
+        return this;
+    }
+
     expression& binary_expression::lhs()
     {
         return *m_lhs;
@@ -655,6 +904,11 @@ namespace boot
         visitor->visit(this);
     }
 
+    unary_expression *unary_expression::is_unary()
+    {
+        return this;
+    }
+
     expression& unary_expression::operand()
     {
         return *m_operand;
@@ -680,6 +934,16 @@ namespace boot
         visitor->visit(this);
     }
 
+    procedure_call *procedure_call::is_call_statement()
+    {
+        return this;
+    }
+
+    procedure_call *procedure_call::is_call_expression()
+    {
+        return this;
+    }
+
     designator_expression& procedure_call::callable()
     {
         return *m_callable;
@@ -705,6 +969,11 @@ namespace boot
         visitor->visit(this);
     }
 
+    cast_expression *cast_expression::is_cast()
+    {
+        return this;
+    }
+
     type_expression& cast_expression::target()
     {
         return *m_target;
@@ -731,6 +1000,11 @@ namespace boot
         visitor->visit(this);
     }
 
+    traits_expression *traits_expression::is_traits()
+    {
+        return this;
+    }
+
     type_expression& traits_expression::type()
     {
         return *m_type;
@@ -765,6 +1039,11 @@ namespace boot
         visitor->visit(this);
     }
 
+    return_statement *return_statement::is_return()
+    {
+        return this;
+    }
+
     expression *return_statement::return_expression()
     {
         return m_return_expression;
@@ -775,15 +1054,20 @@ namespace boot
         delete m_return_expression;
     }
 
+    assign_statement::assign_statement(const struct position position, designator_expression *lvalue,
+            expression *rvalue)
+        : node(position), m_lvalue(lvalue), m_rvalue(rvalue)
+    {
+    }
+
     void assign_statement::accept(parser_visitor *visitor)
     {
         visitor->visit(this);
     }
 
-    assign_statement::assign_statement(const struct position position, designator_expression *lvalue,
-            expression *rvalue)
-        : node(position), m_lvalue(lvalue), m_rvalue(rvalue)
+    assign_statement *assign_statement::is_assign()
     {
+        return this;
     }
 
     variable_expression *designator_expression::is_variable()
@@ -832,6 +1116,11 @@ namespace boot
         visitor->visit(this);
     }
 
+    if_statement *if_statement::is_if()
+    {
+        return this;
+    }
+
     conditional_statements& if_statement::body()
     {
         return *m_body;
@@ -862,6 +1151,11 @@ namespace boot
         visitor->visit(this);
     }
 
+    while_statement *while_statement::is_while()
+    {
+        return this;
+    }
+
     conditional_statements& while_statement::body()
     {
         return *m_body;
diff --git a/boot/semantic.cc b/boot/semantic.cc
deleted file mode 100644
index 55a06ce..0000000
--- a/boot/semantic.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Semantic analysis visitors.
-   Copyright (C) 2025 Free Software Foundation, Inc.
-
-GCC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3, or (at your option)
-any later version.
-
-GCC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3.  If not see
-<http://www.gnu.org/licenses/>.  */
-
-#include "elna/boot/semantic.h"
-
-namespace elna
-{
-namespace boot
-{
-    declaration_visitor::declaration_visitor(std::shared_ptr<symbol_table> table)
-        : table(table)
-    {
-    }
-
-    void declaration_visitor::visit(program *program)
-    {
-    }
-}
-}
diff --git a/boot/symbol.cc b/boot/symbol.cc
deleted file mode 100644
index 9c01ba0..0000000
--- a/boot/symbol.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Symbol definitions.
-   Copyright (C) 2025 Free Software Foundation, Inc.
-
-GCC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3, or (at your option)
-any later version.
-
-GCC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3.  If not see
-<http://www.gnu.org/licenses/>.  */
-
-#include "elna/boot/symbol.h"
-
-namespace elna
-{
-namespace boot
-{
-    type::~type()
-    {
-    }
-
-    info::~info()
-    {
-    }
-
-    type_info::type_info(const std::string& name)
-        : name(name)
-    {
-    }
-}
-}
diff --git a/gcc/Make-lang.in b/gcc/Make-lang.in
index a9fed82..f8f8385 100644
--- a/gcc/Make-lang.in
+++ b/gcc/Make-lang.in
@@ -46,8 +46,6 @@ elna_OBJS = \
 	elna/driver.o \
 	elna/lexer.o \
 	elna/parser.o \
-	elna/semantic.o \
-	elna/symbol.o \
 	elna/result.o \
 	$(END)
 
diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc
index 496a74e..497c92a 100644
--- a/gcc/elna-generic.cc
+++ b/gcc/elna-generic.cc
@@ -38,9 +38,73 @@ namespace elna
 {
 namespace gcc
 {
+    declaration_visitor::declaration_visitor(std::shared_ptr<symbol_table> symbol_table)
+        : symbols(symbol_table)
+    {
+        this->unresolved.insert({ "Int", std::make_shared<type>(elna_int_type_node) });
+        this->unresolved.insert({ "Word", std::make_shared<type>(elna_word_type_node) });
+        this->unresolved.insert({ "Char", std::make_shared<type>(elna_char_type_node) });
+        this->unresolved.insert({ "Bool", std::make_shared<type>(elna_bool_type_node) });
+        this->unresolved.insert({ "Byte", std::make_shared<type>(elna_byte_type_node) });
+        this->unresolved.insert({ "Float", std::make_shared<type>(elna_float_type_node) });
+        this->unresolved.insert({ "String", std::make_shared<type>(elna_string_type_node) });
+    }
+
+    tree get_inner_alias(const type& t)
+    {
+        if (t.reference == nullptr)
+        {
+            return t.resolved;
+        }
+        else
+        {
+            return get_inner_alias(*t.reference);
+        }
+    }
+
+    void declaration_visitor::visit(boot::program *program)
+    {
+        for (boot::type_definition *const type : program->types)
+        {
+            type->accept(this);
+        }
+        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 if (auto alias_node = type->body().is_record())
+            {
+                unresolved_declaration->resolved = make_node(RECORD_TYPE);
+            }
+            else if (auto alias_node = type->body().is_union())
+            {
+                unresolved_declaration->resolved = make_node(UNION_TYPE);
+            }
+        }
+        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, std::make_shared<type>() });
+    }
+
     generic_visitor::generic_visitor(std::shared_ptr<symbol_table> symbol_table)
     {
-        this->symbol_map = symbol_table;
+        this->symbols = symbol_table;
     }
 
     void generic_visitor::build_procedure_call(location_t call_location,
@@ -180,23 +244,6 @@ namespace gcc
             constant->accept(this);
         }
         for (boot::type_definition *const type : program->types)
-        {
-            tree type_node = NULL_TREE;
-
-            if (type->body().is_record())
-            {
-                type_node = make_node(RECORD_TYPE);
-            }
-            else if (type->body().is_union())
-            {
-                type_node = make_node(UNION_TYPE);
-            }
-            if (type_node != NULL_TREE)
-            {
-                this->symbol_map->enter(type->identifier, type_node);
-            }
-        }
-        for (boot::type_definition *const type : program->types)
         {
             type->accept(this);
         }
@@ -229,7 +276,7 @@ namespace gcc
             DECL_CONTEXT(declaration_tree) = fndecl;
             DECL_ARG_TYPE(declaration_tree) = TREE_VALUE(parameter_type);
 
-            this->symbol_map->enter(argument_name, declaration_tree);
+            this->symbols->enter(argument_name, declaration_tree);
             DECL_ARGUMENTS(fndecl) = chainon(DECL_ARGUMENTS(fndecl), declaration_tree);
             parameter_type = TREE_CHAIN(parameter_type);
         }
@@ -269,7 +316,7 @@ namespace gcc
     {
         tree declaration_type = build_procedure_type(definition->heading());
         tree fndecl = build_fn_decl(definition->identifier.c_str(), declaration_type);
-        this->symbol_map->enter(definition->identifier, fndecl);
+        this->symbols->enter(definition->identifier, fndecl);
 
         if (definition->heading().no_return)
         {
@@ -299,7 +346,7 @@ namespace gcc
 
             if (definition->body != nullptr)
             {
-                this->symbol_map->enter(parameter->identifier, declaration_tree);
+                this->symbols->enter(parameter->identifier, declaration_tree);
             }
             argument_chain = chainon(argument_chain, declaration_tree);
             function_args_iter_next(&parameter_type);
@@ -332,7 +379,7 @@ namespace gcc
 
     void generic_visitor::enter_scope()
     {
-        this->symbol_map = std::make_shared<symbol_table>(this->symbol_map);
+        this->symbols = std::make_shared<symbol_table>(this->symbols);
 
         // Chain the binding levels.
         struct binding_level *new_level = ggc_cleared_alloc<binding_level>();
@@ -352,7 +399,7 @@ namespace gcc
             BLOCK_SUPERCONTEXT(it) = new_block;
         }
         tree bind_expr = build3(BIND_EXPR, void_type_node, variables, chain_defer(), new_block);
-        this->symbol_map = this->symbol_map->scope();
+        this->symbols = this->symbols->scope();
 
         f_binding_level = f_binding_level->level_chain;
 
@@ -365,35 +412,7 @@ namespace gcc
 
     tree generic_visitor::lookup(const std::string& name)
     {
-        if (name == "Int")
-        {
-            return elna_int_type_node;
-        }
-        if (name == "Word")
-        {
-            return elna_word_type_node;
-        }
-        if (name == "Char")
-        {
-            return elna_char_type_node;
-        }
-        if (name == "Bool")
-        {
-            return elna_bool_type_node;
-        }
-        if (name == "Byte")
-        {
-            return elna_byte_type_node;
-        }
-        if (name == "Float")
-        {
-            return elna_float_type_node;
-        }
-        if (name == "String")
-        {
-            return elna_string_type_node;
-        }
-        return this->symbol_map->lookup(name);
+        return this->symbols->lookup(name);
     }
 
     void generic_visitor::visit(boot::number_literal<std::int32_t> *literal)
@@ -720,7 +739,7 @@ namespace gcc
 
         tree definition_tree = build_decl(definition_location, CONST_DECL,
                 get_identifier(definition->identifier.c_str()), TREE_TYPE(this->current_expression));
-        auto result = this->symbol_map->enter(definition->identifier, definition_tree);
+        auto result = this->symbols->enter(definition->identifier, definition_tree);
 
         if (result)
         {
@@ -748,12 +767,12 @@ namespace gcc
     void generic_visitor::visit(boot::type_definition *definition)
     {
         location_t definition_location = get_location(&definition->position());
-        this->current_expression = this->symbol_map->lookup(definition->identifier);
+        this->current_expression = lookup(definition->identifier);
         definition->body().accept(this);
 
         tree definition_tree = build_decl(definition_location, TYPE_DECL,
                 get_identifier(definition->identifier.c_str()), this->current_expression);
-        auto result = this->symbol_map->enter(definition->identifier, this->current_expression);
+        auto result = this->symbols->enter(definition->identifier, this->current_expression);
 
         /* if (result)
         { */
@@ -798,7 +817,7 @@ namespace gcc
         location_t declaration_location = get_location(&declaration->position());
         tree declaration_tree = build_decl(declaration_location, VAR_DECL,
                 get_identifier(declaration->identifier.c_str()), this->current_expression);
-        bool result = this->symbol_map->enter(declaration->identifier, declaration_tree);
+        bool result = this->symbols->enter(declaration->identifier, declaration_tree);
 
         if (is_pointer_type(this->current_expression))
         {
@@ -829,7 +848,7 @@ namespace gcc
 
     void generic_visitor::visit(boot::variable_expression *expression)
     {
-        auto symbol = this->lookup(expression->name);
+        auto symbol = lookup(expression->name);
 
         if (symbol == NULL_TREE)
         {
@@ -1122,9 +1141,9 @@ namespace gcc
 
     void generic_visitor::visit(boot::primitive_type_expression *type)
     {
-        tree symbol = this->lookup(type->name);
+        tree symbol = lookup(type->name);
 
-        if (symbol == NULL_TREE && TYPE_P(symbol))
+        if (symbol == NULL_TREE || !TYPE_P(symbol))
         {
             error_at(get_location(&type->position()),
                     "type '%s' not declared", type->name.c_str());
diff --git a/gcc/elna1.cc b/gcc/elna1.cc
index 92203fe..5713719 100644
--- a/gcc/elna1.cc
+++ b/gcc/elna1.cc
@@ -30,7 +30,6 @@ along with GCC; see the file COPYING3.  If not see
 
 #include <fstream>
 #include "elna/boot/driver.h"
-#include "elna/boot/semantic.h"
 #include "elna/gcc/elna-tree.h"
 #include "elna/gcc/elna-generic.h"
 #include "elna/gcc/elna-diagnostic.h"
@@ -89,8 +88,10 @@ static void elna_parse_file(const char *filename)
     }
     else
     {
-        elna::boot::declaration_visitor declaration_visitor{ std::make_shared<elna::boot::symbol_table>() };
-        elna::gcc::generic_visitor generic_visitor{ std::make_shared<elna::gcc::symbol_table>() };
+        std::shared_ptr<elna::gcc::symbol_table> symbol_table = std::make_shared<elna::gcc::symbol_table>();
+
+        elna::gcc::declaration_visitor declaration_visitor{ symbol_table };
+        elna::gcc::generic_visitor generic_visitor{ symbol_table };
 
         declaration_visitor.visit(driver.tree.get());
         generic_visitor.visit(driver.tree.get());
diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h
index f3efc82..0727a39 100644
--- a/include/elna/boot/ast.h
+++ b/include/elna/boot/ast.h
@@ -79,6 +79,8 @@ namespace boot
     class array_access_expression;
     class field_access_expression;
     class dereference_expression;
+    class designator_expression;
+    class literal;
     template<typename T>
     class number_literal;
     class defer_statement;
@@ -132,9 +134,9 @@ namespace boot
         virtual void visit(constant_definition *) override;
         virtual void visit(procedure_definition *) override;
         virtual void visit(type_definition *) override;
-        virtual void visit(traits_expression *) override;
         virtual void visit(procedure_call *) override;
         virtual void visit(cast_expression *) override;
+        virtual void visit(traits_expression *) override;
         virtual void visit(assign_statement *) override;
         virtual void visit(if_statement *) override;
         virtual void visit(while_statement *) override;
@@ -177,8 +179,7 @@ namespace boot
         explicit node(const position position);
 
     public:
-        virtual ~node() = default;
-        virtual void accept(parser_visitor *) = 0;
+        virtual ~node() = 0;
 
         /**
          * \return Node position in the source code.
@@ -188,12 +189,35 @@ namespace boot
 
     class statement : public virtual node
     {
+    public:
+        virtual assign_statement *is_assign();
+        virtual if_statement *is_if();
+        virtual while_statement *is_while();
+        virtual return_statement *is_return();
+        virtual defer_statement *is_defer();
+        virtual procedure_call *is_call_statement();
+
+        void accept(parser_visitor *visitor);
+        ~statement() = 0;
+
     protected:
         statement();
     };
 
     class expression : public virtual node
     {
+    public:
+        virtual cast_expression *is_cast();
+        virtual traits_expression *is_traits();
+        virtual binary_expression *is_binary();
+        virtual unary_expression *is_unary();
+        virtual designator_expression *is_designator();
+        virtual procedure_call *is_call_expression();
+        virtual literal *is_literal();
+
+        void accept(parser_visitor *visitor);
+        ~expression() = 0;
+
     protected:
         expression();
     };
@@ -224,6 +248,8 @@ namespace boot
         virtual std::shared_ptr<union_type_expression> is_union();
         virtual std::shared_ptr<procedure_type_expression> is_procedure();
 
+        void accept(parser_visitor *visitor);
+
     protected:
         type_expression(const struct position position);
     };
@@ -237,7 +263,7 @@ namespace boot
         const std::string name;
 
         primitive_type_expression(const struct position position, const std::string& name);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
         std::shared_ptr<primitive_type_expression> is_primitive() override;
     };
 
@@ -250,7 +276,7 @@ namespace boot
 
         array_type_expression(const struct position position,
                 std::shared_ptr<type_expression> base, const std::uint32_t size);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
         std::shared_ptr<array_type_expression> is_array() override;
 
         type_expression& base();
@@ -262,7 +288,7 @@ namespace boot
 
     public:
         pointer_type_expression(const struct position position, std::shared_ptr<type_expression> base);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
         std::shared_ptr<pointer_type_expression> is_pointer() override;
 
         type_expression& base();
@@ -278,7 +304,7 @@ namespace boot
 
         record_type_expression(const struct position position, fields_t&& fields);
 
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
         std::shared_ptr<record_type_expression> is_record() override;
     };
 
@@ -289,7 +315,7 @@ namespace boot
 
         union_type_expression(const struct position position, fields_t&& fields);
 
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
         std::shared_ptr<union_type_expression> is_union() override;
     };
 
@@ -303,7 +329,7 @@ namespace boot
     public:
         variable_declaration(const struct position position, const std::string& identifier,
                 std::shared_ptr<type_expression> type, const bool exported = false);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
 
         type_expression& variable_type();
     };
@@ -313,6 +339,18 @@ namespace boot
      */
     class literal : public expression
     {
+    public:
+        virtual number_literal<std::int32_t> *is_int() = 0;
+        virtual number_literal<std::uint32_t> *is_word() = 0;
+        virtual number_literal<double> *is_float() = 0;
+        virtual number_literal<bool> *is_bool() = 0;
+        virtual number_literal<unsigned char> *is_char() = 0;
+        virtual number_literal<std::nullptr_t> *is_nil() = 0;
+        virtual number_literal<std::string> *is_string() = 0;
+
+        literal *is_literal() override;
+        void accept(parser_visitor *visitor);
+
     protected:
         literal();
     };
@@ -332,7 +370,7 @@ namespace boot
          */
         constant_definition(const struct position position, const std::string& identifier,
                 const bool exported, literal *body);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
 
         literal& body();
 
@@ -361,7 +399,7 @@ namespace boot
                 std::shared_ptr<type_expression> return_type = nullptr);
         procedure_type_expression(const struct position position, no_return_t);
 
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
         std::shared_ptr<procedure_type_expression> is_procedure() override;
 
         virtual ~procedure_type_expression() override;
@@ -379,7 +417,7 @@ namespace boot
 
         procedure_definition(const struct position position, const std::string& identifier,
                 const bool exported, std::shared_ptr<procedure_type_expression> heading, block *body = nullptr);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
 
         procedure_type_expression& heading();
 
@@ -396,7 +434,7 @@ namespace boot
     public:
         type_definition(const struct position position, const std::string& identifier,
                 const bool exported, std::shared_ptr<type_expression> expression);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
 
         type_expression& body();
     };
@@ -411,7 +449,8 @@ namespace boot
 
     public:
         cast_expression(const struct position position, std::shared_ptr<type_expression> target, expression *value);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
+        cast_expression *is_cast() override;
 
         type_expression& target();
         expression& value();
@@ -428,7 +467,8 @@ namespace boot
 
         traits_expression(const struct position position, const std::string& name,
                 std::shared_ptr<type_expression> type);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
+        traits_expression *is_traits() override;
 
         type_expression& type();
     };
@@ -456,7 +496,8 @@ namespace boot
 
     public:
         return_statement(const struct position position, expression *return_expression);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
+        virtual return_statement *is_return() override;
 
         expression *return_expression();
 
@@ -471,6 +512,10 @@ namespace boot
         virtual field_access_expression *is_field_access();
         virtual dereference_expression *is_dereference();
 
+        designator_expression *is_designator() override;
+        void accept(parser_visitor *visitor);
+        ~designator_expression() = 0;
+
     protected:
         designator_expression();
     };
@@ -481,7 +526,7 @@ namespace boot
         const std::string name;
 
         variable_expression(const struct position position, const std::string& name);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
 
         variable_expression *is_variable() override;
     };
@@ -493,7 +538,7 @@ namespace boot
 
     public:
         array_access_expression(const struct position position, expression *base, expression *index);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
 
         expression& base();
         expression& index();
@@ -511,7 +556,7 @@ namespace boot
     public:
         field_access_expression(const struct position position, expression *base,
                 const std::string& field);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
 
         expression& base();
         std::string& field();
@@ -527,7 +572,7 @@ namespace boot
 
     public:
         dereference_expression(const struct position position, expression *base);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
 
         expression& base();
 
@@ -547,7 +592,9 @@ namespace boot
         std::vector<expression *> arguments;
 
         procedure_call(const struct position position, designator_expression *callable);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
+        virtual procedure_call *is_call_statement() override;
+        virtual procedure_call *is_call_expression() override;
 
         designator_expression& callable();
 
@@ -567,12 +614,13 @@ namespace boot
          */
         assign_statement(const struct position position, designator_expression *lvalue,
                 expression *rvalue);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
 
         designator_expression& lvalue();
         expression& rvalue();
 
         virtual ~assign_statement() override;
+        assign_statement *is_assign() override;
     };
 
     /**
@@ -588,7 +636,8 @@ namespace boot
 
         if_statement(const struct position position, conditional_statements *body,
                 std::vector<statement *> *alternative = nullptr);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
+        virtual if_statement *is_if() override;
 
         conditional_statements& body();
         std::vector<statement *> *alternative();
@@ -606,7 +655,8 @@ namespace boot
     public:
         std::vector<conditional_statements *> branches;
         while_statement(const struct position position, conditional_statements *body);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
+        while_statement *is_while() override;
 
         conditional_statements& body();
 
@@ -621,7 +671,7 @@ namespace boot
         std::vector<statement *> body;
 
         block(const struct position position);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
 
         virtual ~block() override;
     };
@@ -633,7 +683,7 @@ namespace boot
         std::vector<procedure_definition *> procedures;
 
         program(const struct position position);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
 
         virtual ~program() override;
     };
@@ -649,7 +699,91 @@ namespace boot
         {
         }
 
-        virtual void accept(parser_visitor *visitor) override
+        number_literal<std::int32_t> *is_int() override
+        {
+            if (std::is_same<T, std::int32_t>::value)
+            {
+                return reinterpret_cast<number_literal<std::int32_t> *>(this);
+            }
+            else
+            {
+                return nullptr;
+            }
+        }
+
+        number_literal<std::uint32_t> *is_word() override
+        {
+            if (std::is_same<T, std::uint32_t>::value)
+            {
+                return reinterpret_cast<number_literal<std::uint32_t> *>(this);
+            }
+            else
+            {
+                return nullptr;
+            }
+        }
+
+        number_literal<double> *is_float() override
+        {
+            if (std::is_same<T, double>::value)
+            {
+                return reinterpret_cast<number_literal<double> *>(this);
+            }
+            else
+            {
+                return nullptr;
+            }
+        }
+
+        number_literal<bool> *is_bool() override
+        {
+            if (std::is_same<T, bool>::value)
+            {
+                return reinterpret_cast<number_literal<bool> *>(this);
+            }
+            else
+            {
+                return nullptr;
+            }
+        }
+
+        number_literal<unsigned char> *is_char() override
+        {
+            if (std::is_same<T, unsigned char>::value)
+            {
+                return reinterpret_cast<number_literal<unsigned char> *>(this);
+            }
+            else
+            {
+                return nullptr;
+            }
+        }
+
+        number_literal<std::nullptr_t> *is_nil() override
+        {
+            if (std::is_same<T, std::nullptr_t>::value)
+            {
+                return reinterpret_cast<number_literal<std::nullptr_t> *>(this);
+            }
+            else
+            {
+                return nullptr;
+            }
+        }
+
+        number_literal<std::string> *is_string() override
+        {
+            if (std::is_same<T, std::string>::value)
+            {
+                return reinterpret_cast<number_literal<std::string> *>(this);
+            }
+            else
+            {
+                return nullptr;
+            }
+        }
+
+        void accept(parser_visitor *visitor)
         {
             visitor->visit(this);
         }
@@ -661,7 +795,8 @@ namespace boot
         std::vector<statement *> statements;
 
         defer_statement(const struct position position);
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
+        defer_statement *is_defer() override;
 
         virtual ~defer_statement() override;
     };
@@ -676,7 +811,9 @@ namespace boot
         binary_expression(const struct position position, expression *lhs,
                 expression *rhs, const binary_operator operation);
 
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
+        binary_expression *is_binary() override;
+
         expression& lhs();
         expression& rhs();
         binary_operator operation() const;
@@ -693,7 +830,9 @@ namespace boot
         unary_expression(const struct position position, expression *operand,
                 const unary_operator operation);
 
-        virtual void accept(parser_visitor *visitor) override;
+        void accept(parser_visitor *visitor);
+        unary_expression *is_unary() override;
+
         expression& operand();
         unary_operator operation() const;
 
diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h
deleted file mode 100644
index 4401e93..0000000
--- a/include/elna/boot/semantic.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Semantic analysis visitors.
-   Copyright (C) 2025 Free Software Foundation, Inc.
-
-GCC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3, or (at your option)
-any later version.
-
-GCC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3.  If not see
-<http://www.gnu.org/licenses/>.  */
-
-#pragma once
-
-#include "elna/boot/ast.h"
-#include "elna/boot/symbol.h"
-
-namespace elna
-{
-namespace boot
-{
-    class declaration_visitor : public empty_visitor
-    {
-        std::shared_ptr<symbol_table> table;
-
-    public:
-        declaration_visitor(std::shared_ptr<symbol_table> table);
-
-        void visit(program *program) override;
-    };
-}
-}
diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h
index 9d92f3b..15efb2f 100644
--- a/include/elna/boot/symbol.h
+++ b/include/elna/boot/symbol.h
@@ -26,32 +26,6 @@ namespace elna
 {
 namespace boot
 {
-    class info
-    {
-    public:
-        virtual ~info() = 0;
-
-    protected:
-        info() = default;
-    };
-
-    class type
-    {
-    public:
-        virtual ~type() = 0;
-
-    protected:
-        type() = default;
-    };
-
-    class type_info : public info, public type
-    {
-    public:
-        const std::string name;
-
-        type_info(const std::string& name);
-    };
-
     /**
      * Symbol table.
      */
@@ -146,7 +120,5 @@ namespace boot
             return this->outer_scope;
         }
     };
-
-    using symbol_table = symbol_map<std::shared_ptr<info>, std::nullptr_t, nullptr>;
 }
 }
diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h
index 55ff981..921236f 100644
--- a/include/elna/gcc/elna-generic.h
+++ b/include/elna/gcc/elna-generic.h
@@ -27,17 +27,39 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "tree-iterator.h"
 
-#include <forward_list>
+#include <unordered_map>
 #include <string>
 
 namespace elna
 {
 namespace gcc
 {
+    struct type
+    {
+        type() {}
+        type(tree resolved): resolved(resolved) {}
+        type(std::shared_ptr<type> reference): reference(reference) {}
+
+        tree resolved{ NULL_TREE };
+        std::shared_ptr<type> reference;
+    };
+
+    class declaration_visitor final : public boot::empty_visitor
+    {
+        std::shared_ptr<symbol_table> symbols;
+        std::unordered_map<std::string, std::shared_ptr<type>> unresolved;
+
+    public:
+        declaration_visitor(std::shared_ptr<symbol_table> symbol_table);
+
+        void visit(boot::program *program) override;
+        void visit(boot::type_definition *definition) override;
+    };
+
     class generic_visitor final : public boot::empty_visitor
     {
         tree current_expression{ NULL_TREE };
-        std::shared_ptr<symbol_table> symbol_map;
+        std::shared_ptr<symbol_table> symbols;
 
         tree build_label_decl(const char *name, location_t loc);
         tree build_procedure_type(boot::procedure_type_expression& type);
diff --git a/tools/support.rb b/tools/support.rb
index c7d8d78..4774b48 100644
--- a/tools/support.rb
+++ b/tools/support.rb
@@ -6,9 +6,6 @@ require 'uri'
 require 'net/http'
 require 'open3'
 
-LINKER = 'build/rootfs/riscv32-unknown-linux-gnu/bin/ld'
-AS = 'build/rootfs/riscv32-unknown-linux-gnu/bin/as'
-
 TMP = Pathname.new('./build')
 
 class BuildTarget