Generate top-level code from symbol tables
This commit is contained in:
		
							
								
								
									
										8
									
								
								Rakefile
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								Rakefile
									
									
									
									
									
								
							@@ -20,13 +20,15 @@ task default: ['source/main.elna', TMP + 'boot/elna'] do |t|
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
rule(/boot\/.+\.o$/ => ->(file) {
 | 
			
		||||
  Pathname.new('source') +
 | 
			
		||||
  source = Pathname.new('source') +
 | 
			
		||||
    Pathname.new(file).relative_path_from(TMP + 'boot').sub_ext('.elna')
 | 
			
		||||
 | 
			
		||||
  [HOST_INSTALL + 'bin/gelna', source]
 | 
			
		||||
}) do |t|
 | 
			
		||||
  Pathname.new(t.name).dirname.mkpath
 | 
			
		||||
  compiler = HOST_INSTALL + 'bin/gelna'
 | 
			
		||||
  sources, compiler = t.prerequisites.partition { |source| source.end_with? '.elna' }
 | 
			
		||||
 | 
			
		||||
  sh compiler.to_path, '-c', '-o', t.name, *t.prerequisites
 | 
			
		||||
  sh *compiler, '-c', '-O0', '-g', '-o', t.name, *sources
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
file TMP + 'boot/elna' => FileList['source/**/*.elna'].reject { |file|
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,8 @@ along with GCC; see the file COPYING3.  If not see
 | 
			
		||||
 | 
			
		||||
#include "elna/boot/semantic.h"
 | 
			
		||||
 | 
			
		||||
#include <set>
 | 
			
		||||
 | 
			
		||||
namespace elna::boot
 | 
			
		||||
{
 | 
			
		||||
    undeclared_error::undeclared_error(const std::string& identifier, const char *path, const struct position position)
 | 
			
		||||
@@ -46,6 +48,17 @@ namespace elna::boot
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    field_duplication_error::field_duplication_error(const std::string& field_name,
 | 
			
		||||
            const char *path, const struct position)
 | 
			
		||||
        : error(path, position), field_name(field_name)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string field_duplication_error::what() const
 | 
			
		||||
    {
 | 
			
		||||
        return "Repeated field name '" + field_name + "'";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    procedure_type declaration_visitor::build_procedure(procedure_type_expression& type_expression)
 | 
			
		||||
    {
 | 
			
		||||
        procedure_type::return_t result_return;
 | 
			
		||||
@@ -122,15 +135,33 @@ namespace elna::boot
 | 
			
		||||
        this->current_type = type(std::make_shared<array_type>(this->current_type, type_expression->size));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::vector<type_field> declaration_visitor::build_composite_type(const std::vector<field_declaration>& fields)
 | 
			
		||||
    {
 | 
			
		||||
        std::vector<type_field> result;
 | 
			
		||||
        std::set<std::string> field_names;
 | 
			
		||||
 | 
			
		||||
        for (auto& field : fields)
 | 
			
		||||
        {
 | 
			
		||||
            if (field_names.find(field.first) != field_names.cend())
 | 
			
		||||
            {
 | 
			
		||||
                add_error<field_duplication_error>(field.first, this->input_file, field.second->position());
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                field_names.insert(field.first);
 | 
			
		||||
                field.second->accept(this);
 | 
			
		||||
                result.push_back(std::make_pair(field.first, this->current_type));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void declaration_visitor::visit(record_type_expression *type_expression)
 | 
			
		||||
    {
 | 
			
		||||
        auto result_type = std::make_shared<record_type>();
 | 
			
		||||
 | 
			
		||||
        for (auto& field : type_expression->fields)
 | 
			
		||||
        {
 | 
			
		||||
            field.second->accept(this);
 | 
			
		||||
            result_type->fields.push_back(std::make_pair(field.first, this->current_type));
 | 
			
		||||
        }
 | 
			
		||||
        result_type->fields = build_composite_type(type_expression->fields);
 | 
			
		||||
 | 
			
		||||
        this->current_type = type(result_type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -138,11 +169,8 @@ namespace elna::boot
 | 
			
		||||
    {
 | 
			
		||||
        auto result_type = std::make_shared<union_type>();
 | 
			
		||||
 | 
			
		||||
        for (const field_declaration& field : type_expression->fields)
 | 
			
		||||
        {
 | 
			
		||||
            field.second->accept(this);
 | 
			
		||||
            result_type->fields.push_back(std::make_pair(field.first, this->current_type));
 | 
			
		||||
        }
 | 
			
		||||
        result_type->fields = build_composite_type(type_expression->fields);
 | 
			
		||||
 | 
			
		||||
        this->current_type = type(result_type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -179,14 +207,15 @@ namespace elna::boot
 | 
			
		||||
 | 
			
		||||
    void declaration_visitor::visit(procedure_declaration *definition)
 | 
			
		||||
    {
 | 
			
		||||
        std::shared_ptr<procedure_info> info = std::make_shared<procedure_info>(
 | 
			
		||||
                build_procedure(definition->heading()), definition->parameter_names);
 | 
			
		||||
 | 
			
		||||
        this->symbols->enter(definition->identifier.identifier, info);
 | 
			
		||||
        this->symbols = std::make_shared<symbol_table>(this->symbols);
 | 
			
		||||
        std::shared_ptr<procedure_info> info;
 | 
			
		||||
 | 
			
		||||
        if (definition->body.has_value())
 | 
			
		||||
        {
 | 
			
		||||
            info = std::make_shared<procedure_info>(build_procedure(definition->heading()),
 | 
			
		||||
                    definition->parameter_names, this->symbols);
 | 
			
		||||
 | 
			
		||||
            this->symbols = info->symbols;
 | 
			
		||||
 | 
			
		||||
            for (constant_declaration *const constant : definition->body.value().constants())
 | 
			
		||||
            {
 | 
			
		||||
                constant->accept(this);
 | 
			
		||||
@@ -199,8 +228,14 @@ namespace elna::boot
 | 
			
		||||
            {
 | 
			
		||||
                statement->accept(this);
 | 
			
		||||
            }
 | 
			
		||||
            this->symbols = this->symbols->scope();
 | 
			
		||||
        }
 | 
			
		||||
        this->symbols = this->symbols->scope();
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            info = std::make_shared<procedure_info>(build_procedure(definition->heading()),
 | 
			
		||||
                    definition->parameter_names);
 | 
			
		||||
        }
 | 
			
		||||
        this->symbols->enter(definition->identifier.identifier, info);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void declaration_visitor::visit(assign_statement *statement)
 | 
			
		||||
@@ -283,6 +318,13 @@ namespace elna::boot
 | 
			
		||||
                statement->accept(this);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (statement->alternative != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            for (struct statement *const statement : *statement->alternative)
 | 
			
		||||
            {
 | 
			
		||||
                statement->accept(this);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void declaration_visitor::visit(procedure_call *call)
 | 
			
		||||
@@ -330,6 +372,7 @@ namespace elna::boot
 | 
			
		||||
        if (!trait->parameters.empty())
 | 
			
		||||
        {
 | 
			
		||||
            trait->parameters.front()->accept(this);
 | 
			
		||||
            trait->types.push_back(this->current_type);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -337,6 +380,7 @@ namespace elna::boot
 | 
			
		||||
    {
 | 
			
		||||
        expression->value().accept(this);
 | 
			
		||||
        expression->target().accept(this);
 | 
			
		||||
        expression->expression_type = this->current_type;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void declaration_visitor::visit(binary_expression *expression)
 | 
			
		||||
 
 | 
			
		||||
@@ -312,9 +312,14 @@ namespace elna::boot
 | 
			
		||||
        return std::static_pointer_cast<type_info>(shared_from_this());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    procedure_info::procedure_info(const procedure_type symbol, const std::vector<std::string> names)
 | 
			
		||||
    procedure_info::procedure_info(const procedure_type symbol, const std::vector<std::string> names,
 | 
			
		||||
            std::shared_ptr<symbol_table> parent_table)
 | 
			
		||||
        : symbol(symbol), names(names)
 | 
			
		||||
    {
 | 
			
		||||
        if (parent_table != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            this->symbols = std::make_shared<symbol_table>(parent_table);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<procedure_info> procedure_info::is_procedure()
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,8 @@ 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 <algorithm>
 | 
			
		||||
 | 
			
		||||
#include "elna/gcc/elna-builtins.h"
 | 
			
		||||
#include "elna/gcc/elna1.h"
 | 
			
		||||
#include "stor-layout.h"
 | 
			
		||||
@@ -79,4 +81,190 @@ namespace elna::gcc
 | 
			
		||||
 | 
			
		||||
        return symbol_table;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tree build_type_declaration(const std::string& identifier, tree type)
 | 
			
		||||
    {
 | 
			
		||||
        tree definition_tree = build_decl(UNKNOWN_LOCATION, TYPE_DECL,
 | 
			
		||||
                get_identifier(identifier.c_str()), type);
 | 
			
		||||
 | 
			
		||||
        TREE_PUBLIC(definition_tree) = true;
 | 
			
		||||
        if (is_unique_type(type))
 | 
			
		||||
        {
 | 
			
		||||
            TYPE_NAME(type) = DECL_NAME(definition_tree);
 | 
			
		||||
            TYPE_STUB_DECL(type) = definition_tree;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            TYPE_NAME(type) = definition_tree;
 | 
			
		||||
        }
 | 
			
		||||
        return definition_tree;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tree build_composite_type(const std::vector<boot::type_field>& fields, tree composite_type_node,
 | 
			
		||||
            std::shared_ptr<symbol_table> symbols, std::vector<std::string>& path)
 | 
			
		||||
    {
 | 
			
		||||
        for (auto& field : fields)
 | 
			
		||||
        {
 | 
			
		||||
            tree rewritten_field = get_inner_alias(field.second, symbols, path);
 | 
			
		||||
            tree field_declaration = build_field(UNKNOWN_LOCATION,
 | 
			
		||||
                    composite_type_node, field.first, rewritten_field);
 | 
			
		||||
            TYPE_FIELDS(composite_type_node) = chainon(TYPE_FIELDS(composite_type_node), field_declaration);
 | 
			
		||||
        }
 | 
			
		||||
        layout_type(composite_type_node);
 | 
			
		||||
        return composite_type_node;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tree build_procedure_type(const boot::procedure_type& procedure, std::shared_ptr<symbol_table> symbols,
 | 
			
		||||
            std::vector<std::string>& path)
 | 
			
		||||
    {
 | 
			
		||||
        std::vector<tree> parameter_types(procedure.parameters.size());
 | 
			
		||||
 | 
			
		||||
        for (std::size_t i = 0; i < procedure.parameters.size(); ++i)
 | 
			
		||||
        {
 | 
			
		||||
            parameter_types[i] = get_inner_alias(procedure.parameters.at(i), symbols, path);
 | 
			
		||||
        }
 | 
			
		||||
        tree return_type = void_type_node;
 | 
			
		||||
 | 
			
		||||
        if (!procedure.return_type.proper_type.empty())
 | 
			
		||||
        {
 | 
			
		||||
            return_type = get_inner_alias(procedure.return_type.proper_type, symbols, path);
 | 
			
		||||
        }
 | 
			
		||||
        return build_function_type_array(return_type, procedure.parameters.size(), parameter_types.data());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tree get_inner_alias(const boot::type& type, std::shared_ptr<symbol_table> symbols, std::vector<std::string>& path)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto reference = type.get<boot::primitive_type>())
 | 
			
		||||
        {
 | 
			
		||||
            auto looked_up = symbols->lookup(reference->identifier);
 | 
			
		||||
            gcc_assert(looked_up != NULL_TREE);
 | 
			
		||||
 | 
			
		||||
            return TREE_TYPE(looked_up);
 | 
			
		||||
        }
 | 
			
		||||
        else if (auto reference = type.get<boot::record_type>())
 | 
			
		||||
        {
 | 
			
		||||
            tree composite_type_node = make_node(RECORD_TYPE);
 | 
			
		||||
 | 
			
		||||
            build_composite_type(reference->fields, composite_type_node, symbols, path);
 | 
			
		||||
 | 
			
		||||
            return composite_type_node;
 | 
			
		||||
        }
 | 
			
		||||
        else if (auto reference = type.get<boot::union_type>())
 | 
			
		||||
        {
 | 
			
		||||
            tree composite_type_node = make_node(UNION_TYPE);
 | 
			
		||||
 | 
			
		||||
            build_composite_type(reference->fields, composite_type_node, symbols, path);
 | 
			
		||||
 | 
			
		||||
            return composite_type_node;
 | 
			
		||||
        }
 | 
			
		||||
        else if (auto reference = type.get<boot::enumeration_type>())
 | 
			
		||||
        {
 | 
			
		||||
            return build_enumeration_type(reference->members);
 | 
			
		||||
        }
 | 
			
		||||
        else if (auto reference = type.get<boot::pointer_type>())
 | 
			
		||||
        {
 | 
			
		||||
            return build_global_pointer_type(get_inner_alias(reference->base, symbols, path));
 | 
			
		||||
        }
 | 
			
		||||
        else if (auto reference = type.get<boot::array_type>())
 | 
			
		||||
        {
 | 
			
		||||
            tree base = get_inner_alias(reference->base, symbols, path);
 | 
			
		||||
 | 
			
		||||
            return build_static_array_type(base, reference->size);
 | 
			
		||||
        }
 | 
			
		||||
        else if (auto reference = type.get<boot::procedure_type>())
 | 
			
		||||
        {
 | 
			
		||||
            auto procedure = build_procedure_type(*reference, symbols, path);
 | 
			
		||||
 | 
			
		||||
            return build_global_pointer_type(procedure);
 | 
			
		||||
        }
 | 
			
		||||
        else if (auto reference = type.get<boot::alias_type>())
 | 
			
		||||
        {
 | 
			
		||||
            return handle_symbol(reference->name, reference, symbols, path);
 | 
			
		||||
        }
 | 
			
		||||
        return error_mark_node;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tree handle_symbol(const std::string& symbol_name, std::shared_ptr<boot::alias_type> reference,
 | 
			
		||||
            std::shared_ptr<symbol_table> symbols, std::vector<std::string>& path)
 | 
			
		||||
    {
 | 
			
		||||
        path.push_back(symbol_name);
 | 
			
		||||
        std::vector<std::string>::const_iterator head_peace = std::cbegin(path);
 | 
			
		||||
 | 
			
		||||
        if (std::find(std::next(head_peace), std::cend(path), *head_peace) != std::cend(path))
 | 
			
		||||
        {
 | 
			
		||||
            return error_mark_node;
 | 
			
		||||
        }
 | 
			
		||||
        tree looked_up = symbols->lookup(symbol_name);
 | 
			
		||||
 | 
			
		||||
        if (looked_up == NULL_TREE)
 | 
			
		||||
        {
 | 
			
		||||
            looked_up = get_inner_alias(reference->reference, symbols, path);
 | 
			
		||||
 | 
			
		||||
            symbols->enter(symbol_name, build_type_declaration(symbol_name, looked_up));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            looked_up = TREE_TYPE(looked_up);
 | 
			
		||||
        }
 | 
			
		||||
        return looked_up;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void declare_procedure(const std::string& name, const boot::procedure_info& info,
 | 
			
		||||
            std::shared_ptr<symbol_table> symbols)
 | 
			
		||||
    {
 | 
			
		||||
        std::vector<std::string> path;
 | 
			
		||||
        tree declaration_type = gcc::build_procedure_type(info.symbol, symbols, path);
 | 
			
		||||
        tree fndecl = build_fn_decl(name.c_str(), declaration_type);
 | 
			
		||||
        symbols->enter(name, fndecl);
 | 
			
		||||
 | 
			
		||||
        if (info.symbol.return_type.no_return)
 | 
			
		||||
        {
 | 
			
		||||
            TREE_THIS_VOLATILE(fndecl) = 1;
 | 
			
		||||
        }
 | 
			
		||||
        tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, TREE_TYPE(declaration_type));
 | 
			
		||||
        DECL_CONTEXT(resdecl) = fndecl;
 | 
			
		||||
        DECL_RESULT(fndecl) = resdecl;
 | 
			
		||||
 | 
			
		||||
        tree argument_chain = NULL_TREE;
 | 
			
		||||
        function_args_iterator parameter_type;
 | 
			
		||||
        function_args_iter_init(¶meter_type, declaration_type);
 | 
			
		||||
 | 
			
		||||
        std::vector<std::string>::const_iterator parameter_name = info.names.cbegin();
 | 
			
		||||
 | 
			
		||||
        for (boot::type parameter : info.symbol.parameters)
 | 
			
		||||
        {
 | 
			
		||||
            tree declaration_tree = build_decl(UNKNOWN_LOCATION, PARM_DECL,
 | 
			
		||||
                get_identifier(parameter_name->c_str()), function_args_iter_cond(¶meter_type));
 | 
			
		||||
            DECL_CONTEXT(declaration_tree) = fndecl;
 | 
			
		||||
            DECL_ARG_TYPE(declaration_tree) = function_args_iter_cond(¶meter_type);
 | 
			
		||||
 | 
			
		||||
            argument_chain = chainon(argument_chain, declaration_tree);
 | 
			
		||||
            function_args_iter_next(¶meter_type);
 | 
			
		||||
            ++parameter_name;
 | 
			
		||||
        }
 | 
			
		||||
        DECL_ARGUMENTS(fndecl) = argument_chain;
 | 
			
		||||
        TREE_ADDRESSABLE(fndecl) = 1;
 | 
			
		||||
        DECL_EXTERNAL(fndecl) = info.symbols == nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void do_semantic_analysis(std::shared_ptr<boot::symbol_table> info_table, std::shared_ptr<symbol_table> symbols)
 | 
			
		||||
    {
 | 
			
		||||
        for (auto& [symbol_name, symbol_info] : *info_table)
 | 
			
		||||
        {
 | 
			
		||||
            std::vector<std::string> type_path;
 | 
			
		||||
 | 
			
		||||
            if (auto type_info = symbol_info->is_type())
 | 
			
		||||
            {
 | 
			
		||||
                // The top level symbol table has basic (builtin) types in it which are not aliases.
 | 
			
		||||
                if (auto alias_type = type_info->symbol.get<boot::alias_type>())
 | 
			
		||||
                {
 | 
			
		||||
                    handle_symbol(symbol_name, alias_type, symbols, type_path);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else if (auto procedure_info = symbol_info->is_procedure())
 | 
			
		||||
            {
 | 
			
		||||
                declare_procedure(symbol_name, *procedure_info, symbols);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,13 +16,11 @@ along with GCC; see the file COPYING3.  If not see
 | 
			
		||||
<http://www.gnu.org/licenses/>.  */
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <set>
 | 
			
		||||
 | 
			
		||||
#include "elna/gcc/elna-generic.h"
 | 
			
		||||
#include "elna/gcc/elna-diagnostic.h"
 | 
			
		||||
#include "elna/gcc/elna1.h"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include "elna/gcc/elna-builtins.h"
 | 
			
		||||
 | 
			
		||||
#include "ggc.h"
 | 
			
		||||
#include "function.h"
 | 
			
		||||
@@ -38,91 +36,9 @@ along with GCC; see the file COPYING3.  If not see
 | 
			
		||||
 | 
			
		||||
namespace elna::gcc
 | 
			
		||||
{
 | 
			
		||||
    tree get_inner_alias(const boot::type& type, std::shared_ptr<symbol_table> symbols,
 | 
			
		||||
            std::unordered_map<std::string, tree>& unresolved, std::vector<std::string>& path)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto reference = type.get<boot::primitive_type>())
 | 
			
		||||
        {
 | 
			
		||||
            auto looked_up = symbols->lookup(reference->identifier);
 | 
			
		||||
            if (looked_up != NULL_TREE)
 | 
			
		||||
            {
 | 
			
		||||
                return TREE_TYPE(looked_up);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (auto reference = type.get<boot::record_type>())
 | 
			
		||||
        {
 | 
			
		||||
            return make_node(RECORD_TYPE);
 | 
			
		||||
        }
 | 
			
		||||
        else if (auto reference = type.get<boot::union_type>())
 | 
			
		||||
        {
 | 
			
		||||
            return make_node(UNION_TYPE);
 | 
			
		||||
        }
 | 
			
		||||
        else if (auto reference = type.get<boot::enumeration_type>())
 | 
			
		||||
        {
 | 
			
		||||
            return make_node(ENUMERAL_TYPE);
 | 
			
		||||
        }
 | 
			
		||||
        else if (auto reference = type.get<boot::pointer_type>())
 | 
			
		||||
        {
 | 
			
		||||
            return build_global_pointer_type(get_inner_alias(reference->base, symbols, unresolved, path));
 | 
			
		||||
        }
 | 
			
		||||
        else if (auto reference = type.get<boot::array_type>())
 | 
			
		||||
        {
 | 
			
		||||
            tree lower_bound = build_int_cst_type(integer_type_node, 0);
 | 
			
		||||
            tree upper_bound = build_int_cst_type(integer_type_node, reference->size);
 | 
			
		||||
            tree range_type = build_range_type(integer_type_node, lower_bound, upper_bound);
 | 
			
		||||
 | 
			
		||||
            return build_array_type(get_inner_alias(reference->base, symbols, unresolved, path), range_type);
 | 
			
		||||
        }
 | 
			
		||||
        else if (auto reference = type.get<boot::alias_type>())
 | 
			
		||||
        {
 | 
			
		||||
            return handle_symbol(reference->name, reference, symbols, unresolved, path);
 | 
			
		||||
        }
 | 
			
		||||
        return error_mark_node;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tree handle_symbol(const std::string& symbol_name, std::shared_ptr<boot::alias_type> reference,
 | 
			
		||||
            std::shared_ptr<symbol_table> symbols, std::unordered_map<std::string, tree>& unresolved,
 | 
			
		||||
            std::vector<std::string>& path)
 | 
			
		||||
    {
 | 
			
		||||
        path.push_back(symbol_name);
 | 
			
		||||
        std::vector<std::string>::const_iterator head_peace = std::cbegin(path);
 | 
			
		||||
 | 
			
		||||
        if (std::find(std::next(head_peace), std::cend(path), *head_peace) != std::cend(path))
 | 
			
		||||
        {
 | 
			
		||||
            return error_mark_node;
 | 
			
		||||
        }
 | 
			
		||||
        auto looked_up = get_inner_alias(reference->reference, symbols, unresolved, path);
 | 
			
		||||
 | 
			
		||||
        unresolved.insert({ symbol_name, looked_up });
 | 
			
		||||
 | 
			
		||||
        return looked_up;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::unordered_map<std::string, tree> do_semantic_analysis(std::shared_ptr<boot::symbol_table> info_table,
 | 
			
		||||
            std::shared_ptr<symbol_table> symbols)
 | 
			
		||||
    {
 | 
			
		||||
        std::unordered_map<std::string, tree> unresolved;
 | 
			
		||||
 | 
			
		||||
        for (auto& [symbol_name, symbol_info] : *info_table)
 | 
			
		||||
        {
 | 
			
		||||
            std::vector<std::string> type_path;
 | 
			
		||||
 | 
			
		||||
            // The top level symbol table has basic (builtin) types in it which are not aliases.
 | 
			
		||||
            if (auto type_info = symbol_info->is_type())
 | 
			
		||||
            {
 | 
			
		||||
                if (auto alias_type = type_info->symbol.get<boot::alias_type>())
 | 
			
		||||
                {
 | 
			
		||||
                    handle_symbol(symbol_name, alias_type, symbols, unresolved, type_path);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return unresolved;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    generic_visitor::generic_visitor(std::shared_ptr<symbol_table> symbol_table,
 | 
			
		||||
            std::unordered_map<std::string, tree>&& unresolved)
 | 
			
		||||
        : symbols(symbol_table), unresolved(std::move(unresolved))
 | 
			
		||||
            std::shared_ptr<boot::symbol_table> info_table)
 | 
			
		||||
        : symbols(symbol_table), info_table(info_table)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -301,8 +217,8 @@ namespace elna::gcc
 | 
			
		||||
 | 
			
		||||
    void generic_visitor::visit(boot::cast_expression *expression)
 | 
			
		||||
    {
 | 
			
		||||
        expression->target().accept(this);
 | 
			
		||||
        tree cast_target = this->current_expression;
 | 
			
		||||
        std::vector<std::string> path;
 | 
			
		||||
        tree cast_target = get_inner_alias(expression->expression_type, this->symbols->scope(), path);
 | 
			
		||||
 | 
			
		||||
        expression->value().accept(this);
 | 
			
		||||
        tree cast_source = TREE_TYPE(this->current_expression);
 | 
			
		||||
@@ -320,43 +236,6 @@ namespace elna::gcc
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void generic_visitor::declare_procedure(boot::procedure_declaration *const definition)
 | 
			
		||||
    {
 | 
			
		||||
        tree declaration_type = build_procedure_type(definition->heading());
 | 
			
		||||
        tree fndecl = build_fn_decl(definition->identifier.identifier.c_str(), declaration_type);
 | 
			
		||||
        this->symbols->enter(definition->identifier.identifier, fndecl);
 | 
			
		||||
 | 
			
		||||
        if (definition->heading().return_type.no_return)
 | 
			
		||||
        {
 | 
			
		||||
            TREE_THIS_VOLATILE(fndecl) = 1;
 | 
			
		||||
        }
 | 
			
		||||
        tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, TREE_TYPE(declaration_type));
 | 
			
		||||
        DECL_CONTEXT(resdecl) = fndecl;
 | 
			
		||||
        DECL_RESULT(fndecl) = resdecl;
 | 
			
		||||
 | 
			
		||||
        tree argument_chain = NULL_TREE;
 | 
			
		||||
        function_args_iterator parameter_type;
 | 
			
		||||
        function_args_iter_init(¶meter_type, declaration_type);
 | 
			
		||||
 | 
			
		||||
        std::vector<std::string>::const_iterator parameter_name = definition->parameter_names.cbegin();
 | 
			
		||||
 | 
			
		||||
        for (boot::type_expression *parameter : definition->heading().parameters)
 | 
			
		||||
        {
 | 
			
		||||
            tree declaration_tree = build_decl(get_location(¶meter->position()), PARM_DECL,
 | 
			
		||||
                get_identifier(parameter_name->c_str()), function_args_iter_cond(¶meter_type));
 | 
			
		||||
            DECL_CONTEXT(declaration_tree) = fndecl;
 | 
			
		||||
            DECL_ARG_TYPE(declaration_tree) = function_args_iter_cond(¶meter_type);
 | 
			
		||||
 | 
			
		||||
            argument_chain = chainon(argument_chain, declaration_tree);
 | 
			
		||||
            function_args_iter_next(¶meter_type);
 | 
			
		||||
            ++parameter_name;
 | 
			
		||||
        }
 | 
			
		||||
        DECL_ARGUMENTS(fndecl) = argument_chain;
 | 
			
		||||
        TREE_PUBLIC(fndecl) = definition->identifier.exported;
 | 
			
		||||
        TREE_ADDRESSABLE(fndecl) = 1;
 | 
			
		||||
        DECL_EXTERNAL(fndecl) = !definition->body.has_value();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void generic_visitor::visit(boot::program *program)
 | 
			
		||||
    {
 | 
			
		||||
        visit(static_cast<boot::unit *>(program));
 | 
			
		||||
@@ -424,10 +303,6 @@ namespace elna::gcc
 | 
			
		||||
            variable->accept(this);
 | 
			
		||||
        }
 | 
			
		||||
        for (boot::procedure_declaration *const procedure : unit->procedures)
 | 
			
		||||
        {
 | 
			
		||||
            declare_procedure(procedure);
 | 
			
		||||
        }
 | 
			
		||||
        for (boot::procedure_declaration *const procedure : unit->procedures)
 | 
			
		||||
        {
 | 
			
		||||
            procedure->accept(this);
 | 
			
		||||
        }
 | 
			
		||||
@@ -435,16 +310,19 @@ namespace elna::gcc
 | 
			
		||||
 | 
			
		||||
    void generic_visitor::visit(boot::procedure_declaration *definition)
 | 
			
		||||
    {
 | 
			
		||||
        tree fndecl = this->symbols->lookup(definition->identifier.identifier);
 | 
			
		||||
        TREE_PUBLIC(fndecl) = definition->identifier.exported;
 | 
			
		||||
 | 
			
		||||
        if (!definition->body.has_value())
 | 
			
		||||
        {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        tree fndecl = this->symbols->lookup(definition->identifier.identifier);
 | 
			
		||||
 | 
			
		||||
        push_struct_function(fndecl, false);
 | 
			
		||||
        DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc<language_function>();
 | 
			
		||||
 | 
			
		||||
        enter_scope();
 | 
			
		||||
        this->info_table = this->info_table->lookup(definition->identifier.identifier)->is_procedure()->symbols;
 | 
			
		||||
 | 
			
		||||
        tree argument_chain = DECL_ARGUMENTS(fndecl);
 | 
			
		||||
        for (; argument_chain != NULL_TREE; argument_chain = TREE_CHAIN(argument_chain))
 | 
			
		||||
@@ -462,6 +340,7 @@ namespace elna::gcc
 | 
			
		||||
        visit_statements(definition->body.value().body());
 | 
			
		||||
 | 
			
		||||
        tree mapping = leave_scope();
 | 
			
		||||
        this->info_table = this->info_table->scope();
 | 
			
		||||
 | 
			
		||||
        BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl;
 | 
			
		||||
        DECL_INITIAL(fndecl) = BIND_EXPR_BLOCK(mapping);
 | 
			
		||||
@@ -860,85 +739,17 @@ namespace elna::gcc
 | 
			
		||||
        this->current_expression = NULL_TREE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void generic_visitor::visit(boot::type_declaration *definition)
 | 
			
		||||
    void generic_visitor::visit(boot::type_declaration *declaration)
 | 
			
		||||
    {
 | 
			
		||||
        location_t definition_location = get_location(&definition->position());
 | 
			
		||||
        this->current_expression = this->unresolved.at(definition->identifier.identifier);
 | 
			
		||||
        definition->body().accept(this);
 | 
			
		||||
 | 
			
		||||
        tree definition_tree = build_decl(definition_location, TYPE_DECL,
 | 
			
		||||
                get_identifier(definition->identifier.identifier.c_str()), this->current_expression);
 | 
			
		||||
 | 
			
		||||
        TREE_PUBLIC(definition_tree) = definition->identifier.exported;
 | 
			
		||||
        if (is_unique_type(this->current_expression))
 | 
			
		||||
        {
 | 
			
		||||
            TYPE_NAME(this->current_expression) = DECL_NAME(definition_tree);
 | 
			
		||||
            TYPE_STUB_DECL(this->current_expression) = definition_tree;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            TYPE_NAME(this->current_expression) = definition_tree;
 | 
			
		||||
        }
 | 
			
		||||
        auto result = this->symbols->enter(definition->identifier.identifier, definition_tree);
 | 
			
		||||
        gcc_assert(result);
 | 
			
		||||
 | 
			
		||||
        this->current_expression = NULL_TREE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tree generic_visitor::build_procedure_type(boot::procedure_type_expression& type)
 | 
			
		||||
    {
 | 
			
		||||
        std::vector<tree> parameter_types(type.parameters.size());
 | 
			
		||||
 | 
			
		||||
        for (std::size_t i = 0; i < type.parameters.size(); ++i)
 | 
			
		||||
        {
 | 
			
		||||
            type.parameters.at(i)->accept(this);
 | 
			
		||||
            parameter_types[i] = this->current_expression;
 | 
			
		||||
        }
 | 
			
		||||
        tree return_type = void_type_node;
 | 
			
		||||
 | 
			
		||||
        if (type.return_type.proper_type != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            type.return_type.proper_type->accept(this);
 | 
			
		||||
            return_type = this->current_expression;
 | 
			
		||||
        }
 | 
			
		||||
        this->current_expression = NULL_TREE;
 | 
			
		||||
 | 
			
		||||
        return build_function_type_array(return_type, type.parameters.size(), parameter_types.data());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void generic_visitor::build_composite_type(const std::vector<boot::field_declaration>& fields,
 | 
			
		||||
            tree composite_type_node)
 | 
			
		||||
    {
 | 
			
		||||
        std::set<std::string> field_names;
 | 
			
		||||
 | 
			
		||||
        for (auto& field : fields)
 | 
			
		||||
        {
 | 
			
		||||
            if (field_names.find(field.first) != field_names.cend())
 | 
			
		||||
            {
 | 
			
		||||
                error_at(get_location(&field.second->position()), "repeated field name");
 | 
			
		||||
                this->current_expression = error_mark_node;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            field_names.insert(field.first);
 | 
			
		||||
 | 
			
		||||
            field.second->accept(this);
 | 
			
		||||
            if (this->current_expression == NULL_TREE || this->current_expression == error_mark_node)
 | 
			
		||||
            {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            tree field_declaration = build_field(get_location(&field.second->position()),
 | 
			
		||||
                    composite_type_node, field.first, this->current_expression);
 | 
			
		||||
            TYPE_FIELDS(composite_type_node) = chainon(TYPE_FIELDS(composite_type_node), field_declaration);
 | 
			
		||||
            this->current_expression = NULL_TREE;
 | 
			
		||||
        }
 | 
			
		||||
        layout_type(composite_type_node);
 | 
			
		||||
 | 
			
		||||
        this->current_expression = composite_type_node;
 | 
			
		||||
        TREE_PUBLIC(this->symbols->lookup(declaration->identifier.identifier)) = declaration->identifier.exported;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void generic_visitor::visit(boot::variable_declaration *declaration)
 | 
			
		||||
    {
 | 
			
		||||
        declaration->variable_type().accept(this);
 | 
			
		||||
        std::vector<std::string> path;
 | 
			
		||||
        this->current_expression = get_inner_alias(
 | 
			
		||||
                this->info_table->lookup(declaration->identifier.identifier)->is_variable()->symbol,
 | 
			
		||||
                this->symbols->scope(), path);
 | 
			
		||||
 | 
			
		||||
        location_t declaration_location = get_location(&declaration->position());
 | 
			
		||||
        tree declaration_tree = build_decl(declaration_location, VAR_DECL,
 | 
			
		||||
@@ -949,6 +760,7 @@ namespace elna::gcc
 | 
			
		||||
        {
 | 
			
		||||
            DECL_INITIAL(declaration_tree) = elna_pointer_nil_node;
 | 
			
		||||
        }
 | 
			
		||||
        TREE_PUBLIC(declaration_tree) = declaration->identifier.exported;
 | 
			
		||||
        this->current_expression = NULL_TREE;
 | 
			
		||||
        if (!result)
 | 
			
		||||
        {
 | 
			
		||||
@@ -1042,7 +854,8 @@ namespace elna::gcc
 | 
			
		||||
            this->current_expression = error_mark_node;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        trait->parameters.front()->accept(this);
 | 
			
		||||
        std::vector<std::string> path;
 | 
			
		||||
        this->current_expression = get_inner_alias(trait->types.front(), this->symbols, path);
 | 
			
		||||
 | 
			
		||||
        return this->current_expression != error_mark_node;
 | 
			
		||||
    }
 | 
			
		||||
@@ -1106,7 +919,8 @@ namespace elna::gcc
 | 
			
		||||
                this->current_expression = error_mark_node;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            trait->parameters.front()->accept(this);
 | 
			
		||||
            std::vector<std::string> path;
 | 
			
		||||
            this->current_expression = get_inner_alias(trait->types.front(), this->symbols, path);
 | 
			
		||||
            auto field_type = trait->parameters.at(1)->is_named();
 | 
			
		||||
 | 
			
		||||
            if (field_type == nullptr)
 | 
			
		||||
@@ -1383,45 +1197,12 @@ namespace elna::gcc
 | 
			
		||||
 | 
			
		||||
    void generic_visitor::visit(boot::named_type_expression *type)
 | 
			
		||||
    {
 | 
			
		||||
        auto looked_up = this->unresolved.find(type->name);
 | 
			
		||||
        tree symbol;
 | 
			
		||||
 | 
			
		||||
        if (looked_up == this->unresolved.cend())
 | 
			
		||||
        {
 | 
			
		||||
            symbol = this->symbols->lookup(type->name);
 | 
			
		||||
            if (symbol != NULL_TREE)
 | 
			
		||||
            {
 | 
			
		||||
                symbol = TREE_TYPE(symbol);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            symbol = looked_up->second;
 | 
			
		||||
        }
 | 
			
		||||
        if (symbol == NULL_TREE || !TYPE_P(symbol))
 | 
			
		||||
        {
 | 
			
		||||
            error_at(get_location(&type->position()), "Type '%s' not declared", type->name.c_str());
 | 
			
		||||
 | 
			
		||||
            this->current_expression = error_mark_node;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            this->current_expression = symbol;
 | 
			
		||||
        }
 | 
			
		||||
        this->current_expression = TREE_TYPE(this->symbols->lookup(type->name));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void generic_visitor::visit(boot::array_type_expression *type)
 | 
			
		||||
    void generic_visitor::visit(boot::array_type_expression *)
 | 
			
		||||
    {
 | 
			
		||||
        tree lower_bound = build_int_cst_type(integer_type_node, 0);
 | 
			
		||||
        tree upper_bound = build_int_cst_type(integer_type_node, type->size);
 | 
			
		||||
        type->base().accept(this);
 | 
			
		||||
 | 
			
		||||
        if (this->current_expression != NULL_TREE && this->current_expression != error_mark_node)
 | 
			
		||||
        {
 | 
			
		||||
            tree range_type = build_range_type(integer_type_node, lower_bound, upper_bound);
 | 
			
		||||
 | 
			
		||||
            this->current_expression = build_array_type(this->current_expression, range_type);
 | 
			
		||||
        }
 | 
			
		||||
        gcc_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void generic_visitor::visit(boot::pointer_type_expression *type)
 | 
			
		||||
@@ -1434,66 +1215,24 @@ namespace elna::gcc
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void generic_visitor::visit(boot::record_type_expression *type)
 | 
			
		||||
    void generic_visitor::visit(boot::record_type_expression *)
 | 
			
		||||
    {
 | 
			
		||||
        tree composite_type_node = this->current_expression == NULL_TREE
 | 
			
		||||
            ? make_node(RECORD_TYPE)
 | 
			
		||||
            : this->current_expression;
 | 
			
		||||
 | 
			
		||||
        build_composite_type(type->fields, composite_type_node);
 | 
			
		||||
        gcc_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void generic_visitor::visit(boot::union_type_expression *type)
 | 
			
		||||
    void generic_visitor::visit(boot::union_type_expression *)
 | 
			
		||||
    {
 | 
			
		||||
        tree composite_type_node = this->current_expression == NULL_TREE
 | 
			
		||||
            ? make_node(UNION_TYPE)
 | 
			
		||||
            : this->current_expression;
 | 
			
		||||
 | 
			
		||||
        build_composite_type(type->fields, composite_type_node);
 | 
			
		||||
        gcc_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void generic_visitor::visit(boot::procedure_type_expression *type)
 | 
			
		||||
    void generic_visitor::visit(boot::procedure_type_expression *)
 | 
			
		||||
    {
 | 
			
		||||
        tree procedure_type_node = build_procedure_type(*type);
 | 
			
		||||
        this->current_expression = build_global_pointer_type(procedure_type_node);
 | 
			
		||||
        gcc_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void generic_visitor::visit(boot::enumeration_type_expression *type)
 | 
			
		||||
    void generic_visitor::visit(boot::enumeration_type_expression *)
 | 
			
		||||
    {
 | 
			
		||||
        tree composite_type_node = this->current_expression == NULL_TREE
 | 
			
		||||
            ? make_node(ENUMERAL_TYPE)
 | 
			
		||||
            : this->current_expression;
 | 
			
		||||
        location_t enum_location = get_location(&type->position());
 | 
			
		||||
        const tree base_type = integer_type_node;
 | 
			
		||||
 | 
			
		||||
        TREE_TYPE(composite_type_node) = base_type;
 | 
			
		||||
        ENUM_IS_SCOPED(composite_type_node) = 1;
 | 
			
		||||
 | 
			
		||||
        tree *pp = &TYPE_VALUES(composite_type_node);
 | 
			
		||||
        std::size_t order{ 1 };
 | 
			
		||||
 | 
			
		||||
        for (const std::string& member : type->members)
 | 
			
		||||
        {
 | 
			
		||||
            tree member_name = get_identifier(member.c_str());
 | 
			
		||||
            tree member_declaration = build_decl(enum_location, CONST_DECL, member_name, composite_type_node);
 | 
			
		||||
 | 
			
		||||
            DECL_CONTEXT(member_declaration) = composite_type_node;
 | 
			
		||||
            DECL_INITIAL(member_declaration) = build_int_cst_type(composite_type_node, order++);
 | 
			
		||||
            TREE_CONSTANT(member_declaration) = 1;
 | 
			
		||||
            TREE_READONLY(member_declaration) = 1;
 | 
			
		||||
 | 
			
		||||
            TYPE_MAX_VALUE(composite_type_node) = DECL_INITIAL(member_declaration);
 | 
			
		||||
 | 
			
		||||
            *pp = build_tree_list(member_name, member_declaration);
 | 
			
		||||
            pp = &TREE_CHAIN(*pp);
 | 
			
		||||
        }
 | 
			
		||||
        TYPE_MIN_VALUE(composite_type_node) = DECL_INITIAL(TREE_VALUE(TYPE_VALUES(composite_type_node)));
 | 
			
		||||
        TYPE_UNSIGNED(composite_type_node) = TYPE_UNSIGNED(base_type);
 | 
			
		||||
        SET_TYPE_ALIGN(composite_type_node, TYPE_ALIGN(base_type));
 | 
			
		||||
        TYPE_SIZE(composite_type_node) = NULL_TREE;
 | 
			
		||||
        TYPE_PRECISION(composite_type_node) = TYPE_PRECISION(base_type);
 | 
			
		||||
 | 
			
		||||
        layout_type(composite_type_node);
 | 
			
		||||
        gcc_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void generic_visitor::visit(boot::defer_statement *statement)
 | 
			
		||||
 
 | 
			
		||||
@@ -246,6 +246,51 @@ namespace elna::gcc
 | 
			
		||||
        return build_pointer_type_for_mode(type, VOIDmode, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tree build_static_array_type(tree type, const std::uint64_t size)
 | 
			
		||||
    {
 | 
			
		||||
        tree lower_bound = build_int_cst_type(integer_type_node, 0);
 | 
			
		||||
        tree upper_bound = build_int_cst_type(integer_type_node, size);
 | 
			
		||||
        tree range_type = build_range_type(integer_type_node, lower_bound, upper_bound);
 | 
			
		||||
 | 
			
		||||
        return build_array_type(type, range_type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tree build_enumeration_type(const std::vector<std::string>& members)
 | 
			
		||||
    {
 | 
			
		||||
        tree composite_type_node = make_node(ENUMERAL_TYPE);
 | 
			
		||||
        const tree base_type = integer_type_node;
 | 
			
		||||
 | 
			
		||||
        TREE_TYPE(composite_type_node) = base_type;
 | 
			
		||||
        ENUM_IS_SCOPED(composite_type_node) = 1;
 | 
			
		||||
 | 
			
		||||
        tree *pp = &TYPE_VALUES(composite_type_node);
 | 
			
		||||
        std::size_t order{ 1 };
 | 
			
		||||
 | 
			
		||||
        for (const std::string& member : members)
 | 
			
		||||
        {
 | 
			
		||||
            tree member_name = get_identifier(member.c_str());
 | 
			
		||||
            tree member_declaration = build_decl(UNKNOWN_LOCATION, CONST_DECL, member_name, composite_type_node);
 | 
			
		||||
 | 
			
		||||
            DECL_CONTEXT(member_declaration) = composite_type_node;
 | 
			
		||||
            DECL_INITIAL(member_declaration) = build_int_cst_type(composite_type_node, order++);
 | 
			
		||||
            TREE_CONSTANT(member_declaration) = 1;
 | 
			
		||||
            TREE_READONLY(member_declaration) = 1;
 | 
			
		||||
 | 
			
		||||
            TYPE_MAX_VALUE(composite_type_node) = DECL_INITIAL(member_declaration);
 | 
			
		||||
 | 
			
		||||
            *pp = build_tree_list(member_name, member_declaration);
 | 
			
		||||
            pp = &TREE_CHAIN(*pp);
 | 
			
		||||
        }
 | 
			
		||||
        TYPE_MIN_VALUE(composite_type_node) = DECL_INITIAL(TREE_VALUE(TYPE_VALUES(composite_type_node)));
 | 
			
		||||
        TYPE_UNSIGNED(composite_type_node) = TYPE_UNSIGNED(base_type);
 | 
			
		||||
        SET_TYPE_ALIGN(composite_type_node, TYPE_ALIGN(base_type));
 | 
			
		||||
        TYPE_SIZE(composite_type_node) = NULL_TREE;
 | 
			
		||||
        TYPE_PRECISION(composite_type_node) = TYPE_PRECISION(base_type);
 | 
			
		||||
 | 
			
		||||
        layout_type(composite_type_node);
 | 
			
		||||
        return composite_type_node;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tree build_label_decl(const char *name, location_t loc)
 | 
			
		||||
    {
 | 
			
		||||
        auto label_decl = build_decl(loc, LABEL_DECL, get_identifier(name), void_type_node);
 | 
			
		||||
 
 | 
			
		||||
@@ -90,10 +90,9 @@ static void elna_parse_file(const char *filename)
 | 
			
		||||
 | 
			
		||||
            if (declaration_visitor.errors().empty())
 | 
			
		||||
            {
 | 
			
		||||
                std::unordered_map<std::string, tree> unresolved = elna::gcc::do_semantic_analysis(
 | 
			
		||||
                        info_table, symbol_table);
 | 
			
		||||
                elna::gcc::do_semantic_analysis(info_table, symbol_table);
 | 
			
		||||
 | 
			
		||||
                elna::gcc::generic_visitor generic_visitor{ symbol_table, std::move(unresolved) };
 | 
			
		||||
                elna::gcc::generic_visitor generic_visitor{ symbol_table, info_table };
 | 
			
		||||
                generic_visitor.visit(module_tree.get());
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include "elna/boot/symbol.h"
 | 
			
		||||
#include "elna/boot/result.h"
 | 
			
		||||
 | 
			
		||||
namespace elna::boot
 | 
			
		||||
@@ -423,6 +424,8 @@ namespace elna::boot
 | 
			
		||||
        expression *m_value;
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        type expression_type;
 | 
			
		||||
 | 
			
		||||
        cast_expression(const struct position position, type_expression *target, expression *value);
 | 
			
		||||
        void accept(parser_visitor *visitor) override;
 | 
			
		||||
        cast_expression *is_cast() override;
 | 
			
		||||
@@ -438,6 +441,7 @@ namespace elna::boot
 | 
			
		||||
    public:
 | 
			
		||||
        std::vector<type_expression *> parameters;
 | 
			
		||||
        const std::string name;
 | 
			
		||||
        std::vector<type> types;
 | 
			
		||||
 | 
			
		||||
        traits_expression(const struct position position, const std::string& name);
 | 
			
		||||
        ~traits_expression();
 | 
			
		||||
 
 | 
			
		||||
@@ -48,6 +48,16 @@ namespace elna::boot
 | 
			
		||||
        std::string what() const override;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class field_duplication_error : public error
 | 
			
		||||
    {
 | 
			
		||||
        std::string field_name;
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        field_duplication_error(const std::string& field_name, const char *path, const struct position);
 | 
			
		||||
 | 
			
		||||
        std::string what() const override;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class declaration_visitor final : public parser_visitor, public error_container
 | 
			
		||||
    {
 | 
			
		||||
        type current_type;
 | 
			
		||||
@@ -57,6 +67,7 @@ namespace elna::boot
 | 
			
		||||
        std::unordered_map<std::string, std::shared_ptr<alias_type>> unresolved;
 | 
			
		||||
 | 
			
		||||
        procedure_type build_procedure(procedure_type_expression& type_expression);
 | 
			
		||||
        std::vector<type_field> build_composite_type(const std::vector<field_declaration>& fields);
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        explicit declaration_visitor(const char *path, std::shared_ptr<symbol_table> symbols);
 | 
			
		||||
 
 | 
			
		||||
@@ -168,46 +168,6 @@ namespace elna::boot
 | 
			
		||||
        virtual std::shared_ptr<variable_info> is_variable();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class type_info : public info
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        const type symbol;
 | 
			
		||||
 | 
			
		||||
        explicit type_info(const type symbol);
 | 
			
		||||
        std::shared_ptr<type_info> is_type() override;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class procedure_info : public info
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        const procedure_type symbol;
 | 
			
		||||
        const std::vector<std::string> names;
 | 
			
		||||
 | 
			
		||||
        procedure_info(const procedure_type symbol, const std::vector<std::string> names);
 | 
			
		||||
        std::shared_ptr<procedure_info> is_procedure() override;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class constant_info : public info
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        using variant = typename
 | 
			
		||||
            std::variant<std::int32_t, std::uint32_t, double, bool, unsigned char, std::nullptr_t, std::string>;
 | 
			
		||||
 | 
			
		||||
        const variant symbol;
 | 
			
		||||
 | 
			
		||||
        explicit constant_info(const variant& symbol);
 | 
			
		||||
        std::shared_ptr<constant_info> is_constant() override;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class variable_info : public info
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        const type symbol;
 | 
			
		||||
 | 
			
		||||
        variable_info(const type symbol);
 | 
			
		||||
        std::shared_ptr<variable_info> is_variable() override;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Symbol table.
 | 
			
		||||
     */
 | 
			
		||||
@@ -322,5 +282,47 @@ namespace elna::boot
 | 
			
		||||
 | 
			
		||||
    using symbol_table = symbol_map<std::shared_ptr<info>, std::nullptr_t, nullptr>;
 | 
			
		||||
 | 
			
		||||
    class type_info : public info
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        const type symbol;
 | 
			
		||||
 | 
			
		||||
        explicit type_info(const type symbol);
 | 
			
		||||
        std::shared_ptr<type_info> is_type() override;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class procedure_info : public info
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        const procedure_type symbol;
 | 
			
		||||
        const std::vector<std::string> names;
 | 
			
		||||
        std::shared_ptr<symbol_table> symbols;
 | 
			
		||||
 | 
			
		||||
        procedure_info(const procedure_type symbol, const std::vector<std::string> names,
 | 
			
		||||
                std::shared_ptr<symbol_table> parent_table = nullptr);
 | 
			
		||||
        std::shared_ptr<procedure_info> is_procedure() override;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class constant_info : public info
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        using variant = typename
 | 
			
		||||
            std::variant<std::int32_t, std::uint32_t, double, bool, unsigned char, std::nullptr_t, std::string>;
 | 
			
		||||
 | 
			
		||||
        const variant symbol;
 | 
			
		||||
 | 
			
		||||
        explicit constant_info(const variant& symbol);
 | 
			
		||||
        std::shared_ptr<constant_info> is_constant() override;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class variable_info : public info
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        const type symbol;
 | 
			
		||||
 | 
			
		||||
        variable_info(const type symbol);
 | 
			
		||||
        std::shared_ptr<variable_info> is_variable() override;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<symbol_table> builtin_symbol_table();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -29,4 +29,12 @@ namespace elna::gcc
 | 
			
		||||
{
 | 
			
		||||
    void init_ttree();
 | 
			
		||||
    std::shared_ptr<symbol_table> builtin_symbol_table();
 | 
			
		||||
 | 
			
		||||
    void do_semantic_analysis(std::shared_ptr<boot::symbol_table> info_table, std::shared_ptr<symbol_table> symbols);
 | 
			
		||||
    tree handle_symbol(const std::string& symbol_name, std::shared_ptr<boot::alias_type> reference,
 | 
			
		||||
            std::shared_ptr<symbol_table> symbols, std::vector<std::string>& path);
 | 
			
		||||
    tree get_inner_alias(const boot::type& type, std::shared_ptr<symbol_table> symbols,
 | 
			
		||||
            std::vector<std::string>& path);
 | 
			
		||||
    void declare_procedure(const std::string& name, const boot::procedure_info& info,
 | 
			
		||||
            std::shared_ptr<symbol_table> symbols);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -33,22 +33,11 @@ along with GCC; see the file COPYING3.  If not see
 | 
			
		||||
 | 
			
		||||
namespace elna::gcc
 | 
			
		||||
{
 | 
			
		||||
    std::unordered_map<std::string, tree> do_semantic_analysis(std::shared_ptr<boot::symbol_table> info_table,
 | 
			
		||||
            std::shared_ptr<symbol_table> symbols);
 | 
			
		||||
    tree handle_symbol(const std::string& symbol_name, std::shared_ptr<boot::alias_type> reference,
 | 
			
		||||
            std::shared_ptr<symbol_table> symbols, std::unordered_map<std::string, tree>& unresolved,
 | 
			
		||||
            std::vector<std::string>& path);
 | 
			
		||||
 | 
			
		||||
    class generic_visitor final : public boot::parser_visitor
 | 
			
		||||
    {
 | 
			
		||||
        tree current_expression{ NULL_TREE };
 | 
			
		||||
        std::shared_ptr<symbol_table> symbols;
 | 
			
		||||
        std::unordered_map<std::string, tree> unresolved;
 | 
			
		||||
 | 
			
		||||
        void declare_procedure(boot::procedure_declaration *const definition);
 | 
			
		||||
        tree build_procedure_type(boot::procedure_type_expression& type);
 | 
			
		||||
        void build_composite_type(const std::vector<boot::field_declaration>& fields,
 | 
			
		||||
                tree composite_type_node);
 | 
			
		||||
        std::shared_ptr<boot::symbol_table> info_table;
 | 
			
		||||
 | 
			
		||||
        void enter_scope();
 | 
			
		||||
        tree leave_scope();
 | 
			
		||||
@@ -74,8 +63,7 @@ namespace elna::gcc
 | 
			
		||||
        bool assert_constant(location_t expression_location);
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        generic_visitor(std::shared_ptr<symbol_table> symbol_table,
 | 
			
		||||
                std::unordered_map<std::string, tree>&& unresolved);
 | 
			
		||||
        generic_visitor(std::shared_ptr<symbol_table> symbol_table, std::shared_ptr<boot::symbol_table> info_table);
 | 
			
		||||
 | 
			
		||||
        void visit(boot::program *program) override;
 | 
			
		||||
        void visit(boot::procedure_declaration *definition) override;
 | 
			
		||||
@@ -92,7 +80,7 @@ namespace elna::gcc
 | 
			
		||||
        void visit(boot::binary_expression *expression) override;
 | 
			
		||||
        void visit(boot::unary_expression *expression) override;
 | 
			
		||||
        void visit(boot::constant_declaration *definition) override;
 | 
			
		||||
        void visit(boot::type_declaration *definition) override;
 | 
			
		||||
        void visit(boot::type_declaration *declaration) override;
 | 
			
		||||
        void visit(boot::variable_declaration *declaration) override;
 | 
			
		||||
        void visit(boot::variable_expression *expression) override;
 | 
			
		||||
        void visit(boot::array_access_expression *expression) override;
 | 
			
		||||
@@ -104,12 +92,12 @@ namespace elna::gcc
 | 
			
		||||
        void visit(boot::import_declaration *) override;
 | 
			
		||||
        void visit(boot::while_statement *statement) override;
 | 
			
		||||
        void visit(boot::named_type_expression *type) override;
 | 
			
		||||
        void visit(boot::array_type_expression *type) override;
 | 
			
		||||
        void visit(boot::array_type_expression *) override;
 | 
			
		||||
        void visit(boot::pointer_type_expression *type) override;
 | 
			
		||||
        void visit(boot::record_type_expression *type) override;
 | 
			
		||||
        void visit(boot::union_type_expression *type) override;
 | 
			
		||||
        void visit(boot::procedure_type_expression *type) override;
 | 
			
		||||
        void visit(boot::enumeration_type_expression *type) override;
 | 
			
		||||
        void visit(boot::record_type_expression *) override;
 | 
			
		||||
        void visit(boot::union_type_expression *) override;
 | 
			
		||||
        void visit(boot::procedure_type_expression *) override;
 | 
			
		||||
        void visit(boot::enumeration_type_expression *) override;
 | 
			
		||||
        void visit(boot::return_statement *statement) override;
 | 
			
		||||
        void visit(boot::defer_statement *statement) override;
 | 
			
		||||
        void visit(boot::case_statement *statement) override;
 | 
			
		||||
 
 | 
			
		||||
@@ -82,6 +82,8 @@ namespace elna::gcc
 | 
			
		||||
    tree build_field(location_t location, tree record_type, const std::string name, tree type);
 | 
			
		||||
    tree find_field_by_name(location_t expression_location, tree type, const std::string& field_name);
 | 
			
		||||
    tree build_global_pointer_type(tree type);
 | 
			
		||||
    tree build_static_array_type(tree type, const std::uint64_t size);
 | 
			
		||||
    tree build_enumeration_type(const std::vector<std::string>& members);
 | 
			
		||||
    tree build_label_decl(const char *name, location_t loc);
 | 
			
		||||
 | 
			
		||||
    tree extract_constant(tree expression);
 | 
			
		||||
 
 | 
			
		||||
@@ -75,24 +75,24 @@ type
 | 
			
		||||
    _defer,
 | 
			
		||||
    exclamation,
 | 
			
		||||
    arrow,
 | 
			
		||||
	trait,
 | 
			
		||||
	_program,
 | 
			
		||||
	_module,
 | 
			
		||||
	_import
 | 
			
		||||
    trait,
 | 
			
		||||
    _program,
 | 
			
		||||
    _module,
 | 
			
		||||
    _import
 | 
			
		||||
  );
 | 
			
		||||
  Position* = record
 | 
			
		||||
    line: Word;
 | 
			
		||||
	column: Word
 | 
			
		||||
    column: Word
 | 
			
		||||
  end;
 | 
			
		||||
  Location* = record
 | 
			
		||||
    first: Position;
 | 
			
		||||
	last: Position
 | 
			
		||||
    last: Position
 | 
			
		||||
  end;
 | 
			
		||||
  SourceFile* = record
 | 
			
		||||
	buffer: [1024]Char;
 | 
			
		||||
	handle: ^FILE;
 | 
			
		||||
	size: Word;
 | 
			
		||||
	index: Word
 | 
			
		||||
    buffer: [1024]Char;
 | 
			
		||||
    handle: ^FILE;
 | 
			
		||||
    size: Word;
 | 
			
		||||
    index: Word
 | 
			
		||||
  end;
 | 
			
		||||
  FILE* = record end;
 | 
			
		||||
  StringBuffer* = record
 | 
			
		||||
@@ -103,28 +103,28 @@ type
 | 
			
		||||
  SourceCode = record
 | 
			
		||||
    position: Position;
 | 
			
		||||
 | 
			
		||||
	input: Pointer;
 | 
			
		||||
	empty: proc(Pointer) -> Bool;
 | 
			
		||||
	advance: proc(Pointer);
 | 
			
		||||
	head: proc(Pointer) -> Char
 | 
			
		||||
    input: Pointer;
 | 
			
		||||
    empty: proc(Pointer) -> Bool;
 | 
			
		||||
    advance: proc(Pointer);
 | 
			
		||||
    head: proc(Pointer) -> Char
 | 
			
		||||
  end;
 | 
			
		||||
  Token* = record
 | 
			
		||||
    kind: TokenKind;
 | 
			
		||||
    value: union
 | 
			
		||||
      int_value: Int;
 | 
			
		||||
      string: String;
 | 
			
		||||
	  boolean_value: Bool;
 | 
			
		||||
	  char_value: Char
 | 
			
		||||
      boolean_value: Bool;
 | 
			
		||||
      char_value: Char
 | 
			
		||||
    end;
 | 
			
		||||
	location: Location
 | 
			
		||||
    location: Location
 | 
			
		||||
  end;
 | 
			
		||||
  CommandLine* = record
 | 
			
		||||
    input: ^Char;
 | 
			
		||||
	lex: Bool;
 | 
			
		||||
	parse: Bool
 | 
			
		||||
    lex: Bool;
 | 
			
		||||
    parse: Bool
 | 
			
		||||
  end;
 | 
			
		||||
  Lexer* = record
 | 
			
		||||
	length: Word;
 | 
			
		||||
    length: Word;
 | 
			
		||||
    data: ^Token
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
@@ -314,7 +314,7 @@ begin
 | 
			
		||||
 | 
			
		||||
  if source_file^.index > source_file^.size then
 | 
			
		||||
    source_file^.size := fread(cast(@source_file^.buffer: Pointer), 1u, 1024u, source_file^.handle);
 | 
			
		||||
	source_file^.index := 1u
 | 
			
		||||
	  source_file^.index := 1u
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  return source_file^.size = 0u
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user