elna/include/elna/boot/symbol.h

316 lines
7.8 KiB
C++

/* 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/>. */
#pragma once
#include <cstdint>
#include <unordered_map>
#include <string>
#include <memory>
#include <vector>
#include "elna/boot/result.h"
namespace elna::boot
{
class alias_type;
class primitive_type;
class record_type;
class union_type;
class pointer_type;
class array_type;
class procedure_type;
class enumeration_type;
class type
{
enum class type_tag
{
empty,
alias,
primitive,
record,
_union,
pointer,
array,
procedure,
enumeration
};
type_tag tag{ type_tag::empty };
union
{
std::weak_ptr<alias_type> alias;
std::shared_ptr<primitive_type> primitive;
std::shared_ptr<record_type> record;
std::shared_ptr<union_type> _union;
std::shared_ptr<pointer_type> pointer;
std::shared_ptr<array_type> array;
std::shared_ptr<procedure_type> procedure;
std::shared_ptr<enumeration_type> enumeration;
};
void copy(const type& other);
void move(type&& other);
public:
type();
explicit type(std::shared_ptr<alias_type> alias);
explicit type(std::shared_ptr<primitive_type> primitive);
explicit type(std::shared_ptr<record_type> record);
explicit type(std::shared_ptr<union_type> _union);
explicit type(std::shared_ptr<pointer_type> pointer);
explicit type(std::shared_ptr<array_type> array);
explicit type(std::shared_ptr<procedure_type> procedure);
explicit type(std::shared_ptr<enumeration_type> enumeration);
type(const type& other);
type& operator=(const type& other);
type(type&& other);
type& operator=(type&& other);
bool operator==(const std::nullptr_t&);
~type();
template<typename T>
std::shared_ptr<T> get() const;
bool empty() const;
};
struct alias_type
{
const std::string name;
type reference;
explicit alias_type(const std::string& name);
};
struct pointer_type
{
const type base;
explicit pointer_type(type base);
};
struct array_type
{
const type base;
const std::uint64_t size;
array_type(type base, std::uint64_t size);
};
struct primitive_type
{
const std::string identifier;
explicit primitive_type(const std::string& identifier);
};
using type_field = std::pair<std::string, type>;
struct record_type
{
std::vector<type_field> fields;
};
struct union_type
{
std::vector<type_field> fields;
};
struct procedure_type
{
using return_t = return_declaration<type>;
std::vector<type> parameters;
const return_t return_type;
procedure_type(return_t return_type = return_t());
};
struct enumeration_type
{
std::vector<std::string> members;
explicit enumeration_type(const std::vector<std::string>& members);
};
class type_info;
class procedure_info;
class constant_info;
class info : public std::enable_shared_from_this<info>
{
public:
virtual ~info() = 0;
virtual std::shared_ptr<type_info> is_type();
virtual std::shared_ptr<procedure_info> is_procedure();
};
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);
};
/**
* Symbol table.
*/
template<typename T, typename U, U nothing>
class symbol_map
{
public:
using symbol_ptr = typename std::enable_if<
std::is_convertible<U, T>::value || std::is_assignable<T, U>::value,
T
>::type;
using iterator = typename std::unordered_map<std::string, symbol_ptr>::iterator;
using const_iterator = typename std::unordered_map<std::string, symbol_ptr>::const_iterator;
private:
std::unordered_map<std::string, symbol_ptr> entries;
std::shared_ptr<symbol_map> outer_scope;
public:
/**
* Constructs a new symbol with an optional outer scope.
*
* \param scope Outer scope.
*/
explicit symbol_map(std::shared_ptr<symbol_map> scope = nullptr)
: outer_scope(scope)
{
}
iterator begin()
{
return this->entries.begin();
}
iterator end()
{
return this->entries.end();
}
const_iterator cbegin() const
{
return this->entries.cbegin();
}
const_iterator cend() const
{
return this->entries.cend();
}
/**
* \return Symbol count in the current scope.
*/
std::size_t size() const
{
return this->entries.size();
}
/**
* Looks for symbol in the table by name. Returns nothing if the symbol
* can not be found.
*
* \param name Symbol name.
* \return Symbol from the table if found.
*/
symbol_ptr lookup(const std::string& name)
{
auto entry = entries.find(name);
if (entry != entries.cend())
{
return entry->second;
}
if (this->outer_scope != nullptr)
{
return this->outer_scope->lookup(name);
}
return nothing;
}
/**
* \param name Symbol name.
* \return Whether the table contains a symbol with the given name.
*/
bool contains(const std::string& name)
{
return lookup(name) != nothing;
}
/**
* Registers new symbol.
*
* \param name Symbol name.
* \param entry Symbol information.
*
* \return Whether the insertion took place.
*/
bool enter(const std::string& name, symbol_ptr entry)
{
return lookup(name) == nothing && entries.insert({ name, entry }).second;
}
/**
* Returns the outer scope or nullptr if the this is the global scope.
*
* \return Outer scope.
*/
std::shared_ptr<symbol_map> scope()
{
return this->outer_scope;
}
};
using symbol_table = symbol_map<std::shared_ptr<info>, std::nullptr_t, nullptr>;
std::shared_ptr<symbol_table> builtin_symbol_table();
}