/* 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
. */
#include "elna/boot/symbol.h"
namespace elna::boot
{
type::type(std::shared_ptr alias)
: payload(alias)
{
}
type::type(std::shared_ptr primitive)
: payload(primitive)
{
}
type::type(std::shared_ptr record)
: payload(record)
{
}
type::type(std::shared_ptr pointer)
: payload(pointer)
{
}
type::type(std::shared_ptr constant)
: payload(constant)
{
}
type::type(std::shared_ptr array)
: payload(array)
{
}
type::type(std::shared_ptr procedure)
: payload(procedure)
{
}
type::type(std::shared_ptr enumeration)
: payload(enumeration)
{
}
template
std::shared_ptr type::get() const
{
if constexpr (std::is_same_v)
{
if (auto *wp = std::get_if>(&payload))
return wp->lock();
return nullptr;
}
else
{
if (auto *sp = std::get_if>(&payload))
return *sp;
return nullptr;
}
}
// Explicit instantiation for all types used by callers.
template std::shared_ptr type::get() const;
template std::shared_ptr type::get() const;
template std::shared_ptr type::get() const;
template std::shared_ptr type::get() const;
template std::shared_ptr type::get() const;
template std::shared_ptr type::get() const;
template std::shared_ptr type::get() const;
template std::shared_ptr type::get() const;
bool type::operator==(const std::nullptr_t&) const
{
return empty();
}
bool type::operator==(const type& other) const
{
type resolved_this = resolve_aliases(*this);
type resolved_that = resolve_aliases(other);
if (auto left_record = resolved_this.get())
{
return left_record == resolved_that.get();
}
if (auto left_primitive = resolved_this.get())
{
auto right_primitive = resolved_that.get();
return right_primitive != nullptr && left_primitive->identifier == right_primitive->identifier;
}
if (auto left_enumeration = resolved_this.get())
{
return left_enumeration == resolved_that.get();
}
if (auto left_pointer = resolved_this.get())
{
auto right_pointer = resolved_that.get();
return right_pointer != nullptr && left_pointer->base == right_pointer->base;
}
if (auto left_const = resolved_this.get())
{
auto right_const = resolved_that.get();
return right_const != nullptr && left_const->unqualified == right_const->unqualified;
}
if (auto left_array = resolved_this.get())
{
auto right_array = resolved_that.get();
return right_array != nullptr && left_array->size == right_array->size
&& left_array->base == right_array->base;
}
if (auto left_procedure = resolved_this.get())
{
auto right_procedure = resolved_that.get();
return right_procedure != nullptr && left_procedure->return_type == right_procedure->return_type
&& left_procedure->parameters == right_procedure->parameters;
}
return resolved_this.empty() && resolved_that.empty();
}
bool type::empty() const
{
return std::holds_alternative(payload);
}
std::string type::to_string() const
{
return std::visit([](const auto& p) -> std::string {
using T = std::decay_t;
if constexpr (std::is_same_v)
return "";
else if constexpr (std::is_same_v>)
return p.lock()->name;
else if constexpr (std::is_same_v>)
return p->identifier;
else if constexpr (std::is_same_v>)
return "^" + p->base.to_string();
else if constexpr (std::is_same_v>)
return "const " + p->unqualified.to_string();
else if constexpr (std::is_same_v>)
return "[" + std::to_string(p->size) + "]" + p->base.to_string();
else if constexpr (std::is_same_v>)
{
if (p->base.empty())
return "record ... end";
else
return "record(" + p->base.to_string() + ") ... end";
}
else if constexpr (std::is_same_v>)
{
std::string result = "proc(";
for (std::size_t i = 0; i < p->parameters.size(); ++i)
{
if (i > 0) result += ", ";
result += p->parameters[i].to_string();
}
result += ")";
if (p->return_type.no_return)
result += ": !";
else if (!p->return_type.proper_type.empty())
result += ": " + p->return_type.proper_type.to_string();
return result;
}
else if constexpr (std::is_same_v>)
return "(enumeration)";
}, payload);
}
alias_type::alias_type(const std::string& name)
: name(name), referent()
{
}
pointer_type::pointer_type(type base)
: base(base)
{
}
constant_type::constant_type(type unqualified)
: unqualified(unqualified)
{
}
array_type::array_type(type base, std::uint64_t size)
: base(base), size(size)
{
}
primitive_type::primitive_type(const std::string& identifier)
: identifier(identifier)
{
}
record_type::record_type(type base)
: base(base)
{
}
procedure_type::procedure_type(return_t return_type)
: return_type(return_type)
{
}
enumeration_type::enumeration_type(const std::vector& members)
: members(members)
{
}
info::~info()
{
}
std::shared_ptr info::is_type()
{
return nullptr;
}
std::shared_ptr info::is_procedure()
{
return nullptr;
}
std::shared_ptr info::is_variable()
{
return nullptr;
}
type_info::type_info(const type symbol)
: symbol(symbol)
{
}
std::shared_ptr type_info::is_type()
{
return std::static_pointer_cast(shared_from_this());
}
procedure_info::procedure_info(const procedure_type symbol, const std::vector names,
std::shared_ptr scope)
: symbol(symbol), names(names), scope(scope)
{
}
std::shared_ptr procedure_info::is_procedure()
{
return std::static_pointer_cast(shared_from_this());
}
bool procedure_info::is_extern() const
{
return this->scope == nullptr;
}
variable_info::variable_info(const type symbol, bool is_extern)
: symbol(symbol), is_extern(is_extern)
{
}
std::shared_ptr variable_info::is_variable()
{
return std::static_pointer_cast(shared_from_this());
}
std::shared_ptr builtin_symbol_table()
{
auto result = std::make_shared();
result->enter("Int", std::make_shared(type(std::make_shared("Int"))));
result->enter("Word", std::make_shared(type(std::make_shared("Word"))));
result->enter("Char", std::make_shared(type(std::make_shared("Char"))));
result->enter("Pointer", std::make_shared(type(std::make_shared("Pointer"))));
result->enter("Float", std::make_shared(type(std::make_shared("Float"))));
result->enter("String", std::make_shared(type(std::make_shared("String"))));
type boolean = type(std::make_shared("Bool"));
result->enter("Bool", std::make_shared(boolean));
procedure_type assert_symbol{ procedure_type::return_t() };
assert_symbol.parameters.push_back(boolean);
std::shared_ptr assert_info = std::make_shared(assert_symbol,
std::vector{ "condition" });
result->enter("assert", assert_info);
return result;
}
symbol_bag::symbol_bag(forward_table&& unresolved, std::shared_ptr global_table)
: unresolved(unresolved)
{
this->symbols = std::make_shared(global_table);
}
std::shared_ptr symbol_bag::lookup(const std::string& name)
{
for (auto import_bag : this->imports)
{
if (auto result = import_bag->lookup(name))
{
return result;
}
}
return this->symbols->lookup(name);
}
bool symbol_bag::enter(const std::string& name, std::shared_ptr entry)
{
return this->symbols->enter(name, entry);
}
std::shared_ptr symbol_bag::enter()
{
this->symbols = std::make_shared(this->symbols);
return this->symbols;
}
void symbol_bag::enter(std::shared_ptr child)
{
this->symbols = child;
}
std::shared_ptr symbol_bag::leave()
{
std::shared_ptr result = this->symbols;
this->symbols = result->scope();
return result;
}
std::shared_ptr symbol_bag::declared(const std::string& symbol_name)
{
auto unresolved_alias = this->unresolved.find(symbol_name);
return unresolved_alias == this->unresolved.end() ? std::shared_ptr() : unresolved_alias->second;
}
std::shared_ptr symbol_bag::resolve(const std::string& symbol_name, type& resolution)
{
auto unresolved_declaration = this->unresolved.at(symbol_name);
unresolved_declaration->referent = resolution;
return unresolved_declaration;
}
void symbol_bag::add_import(const symbol_bag& bag)
{
this->imports.push_front(bag.exported_symbols());
}
std::shared_ptr symbol_bag::exported_symbols() const
{
if (!m_exported)
{
m_exported = std::make_shared(symbols->scope());
for (const auto& [name, info] : *symbols)
{
if (info->exported)
{
m_exported->enter(name, info);
}
}
}
return m_exported;
}
type resolve_underlying_type(std::shared_ptr alias)
{
return resolve_underlying_type(alias->referent);
}
type resolve_underlying_type(const type& alias)
{
type resolved_alias = resolve_aliases(alias);
if (auto qualified = resolved_alias.get())
{
return resolve_underlying_type(qualified->unqualified);
}
else
{
return resolved_alias;
}
}
type resolve_aliases(const type& checked)
{
if (auto alias = checked.get())
{
return resolve_aliases(alias->referent);
}
return checked;
}
bool is_primitive_type(const type& checked, const std::string& name)
{
if (auto primitive_checked = checked.get())
{
return primitive_checked->identifier == name;
}
return false;
}
bool is_any_pointer_type(const type& checked)
{
return checked.get() != nullptr
|| checked.get() != nullptr
|| is_primitive_type(resolve_underlying_type(checked), "Pointer");
}
}