316 lines
7.8 KiB
C++
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();
|
|
}
|