/* 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"
#include
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 slice)
: payload(slice)
{
}
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 (const auto *weak_pointer = std::get_if>(&payload)) {
return weak_pointer->lock();
}
return nullptr;
}
else
{
if (auto *shared_pointer = std::get_if>(&payload)) {
return *shared_pointer;
}
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;
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 const resolved_this = resolve_aliases(*this);
type const 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_slice = resolved_this.get())
{
auto right_slice = resolved_that.get();
return right_slice != nullptr && left_slice->base == right_slice->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& payload) -> std::string {
using T = std::decay_t;
if constexpr (std::is_same_v)
{
return "";
}
else if constexpr (std::is_same_v>)
{
return payload.lock()->name;
}
else if constexpr (std::is_same_v>)
{
return payload->identifier;
}
else if constexpr (std::is_same_v>)
{
return "^" + payload->base.to_string();
}
else if constexpr (std::is_same_v>)
{
return "const " + payload->unqualified.to_string();
}
else if constexpr (std::is_same_v>)
{
return "[" + std::to_string(payload->size) + "]" + payload->base.to_string();
}
else if constexpr (std::is_same_v>)
{
return "[]" + payload->base.to_string();
}
else if constexpr (std::is_same_v>)
{
return payload->base.empty()
? "record ... end"
: "record(" + payload->base.to_string() + ") ... end";
}
else if constexpr (std::is_same_v>)
{
std::string result = "proc(";
for (std::size_t i = 0; i < payload->parameters.size(); ++i)
{
if (i > 0) { result += ", ";
}
result += payload->parameters[i].to_string();
}
result += ")";
if (payload->return_type.no_return) {
result += ": !";
} else if (!payload->return_type.proper_type.empty()) {
result += ": " + payload->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)
{
}
pointer_type::pointer_type(type base)
: base(std::move(base))
{
}
constant_type::constant_type(type unqualified)
: unqualified(std::move(unqualified))
{
}
array_type::array_type(type base, std::uint64_t size)
: base(std::move(base)), size(size)
{
}
slice_type::slice_type(type base)
: base(std::move(base))
{
}
primitive_type::primitive_type(const std::string& identifier)
: identifier(identifier)
{
}
record_type::record_type(type base)
: base(std::move(base))
{
}
procedure_type::procedure_type(return_t return_type)
: return_type(std::move(return_type))
{
}
enumeration_type::enumeration_type(const std::vector& members)
: members(members)
{
}
info::~info() = default;
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(std::move(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"))));
type const 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 const assert_info = std::make_shared(assert_symbol,
std::vector{ "condition" });
result->enter("assert", assert_info);
return result;
}
symbol_bag::symbol_bag(forward_table&& unresolved, const 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 (const 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, const 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 = std::move(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(const 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_numeric_type(const type& checked)
{
type const resolved = resolve_underlying_type(checked);
return is_primitive_type(resolved, "Int")
|| is_primitive_type(resolved, "Word")
|| is_primitive_type(resolved, "Float");
}
bool is_integral_type(const type& checked)
{
type const resolved = resolve_underlying_type(checked);
return is_primitive_type(resolved, "Int")
|| is_primitive_type(resolved, "Word");
}
bool is_discrete_type(const type& checked)
{
type const resolved = resolve_underlying_type(checked);
return is_primitive_type(resolved, "Int")
|| is_primitive_type(resolved, "Word")
|| is_primitive_type(resolved, "Bool")
|| is_primitive_type(resolved, "Char");
}
bool is_any_pointer_type(const type& checked)
{
return checked.get() != nullptr
|| checked.get() != nullptr
|| is_primitive_type(resolve_underlying_type(checked), "Pointer");
}
}