elna/include/elna/source/result.hpp

214 lines
4.6 KiB
C++

#pragma once
#include <cstddef>
#include <cstdint>
#include <variant>
#include <list>
#include <memory>
#include <string>
#include <type_traits>
#include <unordered_map>
namespace elna::source
{
/**
* Position in the source text.
*/
struct position
{
/// Line.
std::size_t line = 1;
/// Column.
std::size_t column = 1;
};
/**
* A compilation error consists of an error message and position.
*/
class error
{
position m_position;
protected:
/**
* \param position Error position in the source text.
*/
error(const position position);
public:
/// Error text.
virtual std::string what() const = 0;
/// Error line in the source text.
std::size_t line() const noexcept;
/// Error column in the source text.
std::size_t column() const noexcept;
};
template<typename T>
struct result
{
using E = std::list<std::unique_ptr<source::error>>;
template<typename... Args, typename = std::enable_if<std::is_constructible_v<T, Args...>>>
explicit result(std::in_place_t, Args&&... arguments)
: payload(std::in_place_type<T>, std::forward<Args>(arguments)...)
{
}
explicit result(T&& result)
: payload(std::move(result))
{
}
template<typename U, typename = std::enable_if<std::is_base_of_v<error, U>>>
explicit result(U&& first)
: payload(E())
{
errors().emplace_back(std::make_unique<U>(first));
}
bool has_errors() const noexcept
{
return std::holds_alternative<E>(payload);
}
bool is_success() const noexcept
{
return std::holds_alternative<T>(payload);
}
T& success()
{
return std::get<T>(payload);
}
E& errors()
{
return std::get<E>(payload);
}
private:
std::variant<T, E> payload;
};
class name_collision final : public error
{
position previous;
std::string name;
public:
name_collision(const std::string& name, const position current, const position previous);
std::string what() const override;
};
/**
* Generic language entity information.
*/
class info
{
public:
virtual ~info() = 0;
protected:
info();
};
/**
* Constant information.
*/
class constant_info final : public info
{
std::int32_t m_value;
public:
constant_info(const std::int32_t value);
~constant_info() override;
std::int32_t value() const noexcept;
};
/**
* Variable information.
*/
struct variable_info final : public info
{
std::ptrdiff_t offset{ 0 };
~variable_info() override;
};
/**
* Procedure information.
*/
class procedure_info final : public info
{
std::size_t local_stack_size{ 0 };
public:
~procedure_info() override;
void stack_size(const std::size_t size) noexcept;
std::size_t stack_size() const noexcept;
};
/**
* Intrinsic and external procedure information.
*/
class intrinsic_info final : public info
{
public:
~intrinsic_info() override;
};
/**
* Symbol table.
*/
class symbol_table
{
std::unordered_map<std::string, std::shared_ptr<info>> entries;
public:
symbol_table();
std::shared_ptr<info> lookup(const std::string& name);
void enter(const std::string& name, std::shared_ptr<info> entry);
};
struct writer
{
/**
* Writes data to the table and saves it under the given label.
*
* \param label Symbol name.
* \param data Data to be written.
* \param size Data size.
*
* \return New size of the table.
*/
virtual std::size_t sink(const std::string& label, const std::byte *data, std::size_t size) = 0;
/**
* Writes data and returns a label under that the data can be accessed.
*
* \param data Data to be written.
* \param size Data size.
*
* \return Label for the symbol.
*/
virtual std::string_view sink(const std::byte *data, std::size_t size) = 0;
/**
* Creates an external symbol.
*/
virtual void sink(const std::string& label) = 0;
/**
* \return Actual size of the text section.
*/
virtual std::size_t size() const = 0;
};
}