Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.10)
project(ZenKit VERSION 1.3.0)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)

option(ZK_BUILD_EXAMPLES "ZenKit: Build the examples." OFF)
option(ZK_BUILD_TESTS "ZenKit: Build the test suite." ON)
Expand Down
21 changes: 19 additions & 2 deletions include/zenkit/DaedalusScript.hh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <cstdint>
#include <functional>
#include <memory>
#include <span>
#include <string>
#include <typeinfo>
#include <unordered_map>
Expand Down Expand Up @@ -58,6 +59,7 @@ namespace zenkit {
static constexpr auto EXTERNAL = 1U << 3U; ///< The symbol refers to an external function.
static constexpr auto MERGED = 1U << 4U; ///< Unused.
static constexpr auto TRAP_ACCESS = 1U << 6U; ///< VM should call trap callback, when symbol accessed.
static constexpr auto FUNC_LOCALS = 1U << 7U; ///< VM should call trap callback, when symbol accessed.

// Deprecated entries.
ZKREM("renamed to DaedalusSymbolFlag::CONST") static constexpr auto const_ = CONST;
Expand Down Expand Up @@ -556,6 +558,10 @@ namespace zenkit {
/// \param enable true to enable and false to disable
ZKAPI void set_access_trap_enable(bool enable) noexcept;

/// \brief Allows function associated with this symbol to stash local variables on a stack during recursion.
/// \param enable true to enable and false to disable
ZKAPI void set_local_variables_enable(bool enable) noexcept;

/// \brief Tests whether the symbol is a constant.
/// \return `true` if the symbol is a constant, `false` if not.
[[nodiscard]] ZKAPI bool is_const() const noexcept {
Expand Down Expand Up @@ -598,6 +604,12 @@ namespace zenkit {
return (_m_flags & DaedalusSymbolFlag::RETURN) != 0;
}

/// \brief brief Tests whether the symbol has local-variables enabled.
/// \return return `true` if enabled, `false` if not.
[[nodiscard]] ZKAPI bool has_local_variables_enabled() const noexcept {
return (_m_flags & DaedalusSymbolFlag::FUNC_LOCALS) != 0;
}

/// \return The name of the symbol.
[[nodiscard]] ZKAPI std::string const& name() const noexcept {
return _m_name;
Expand Down Expand Up @@ -799,7 +811,7 @@ namespace zenkit {
/// \brief Looks for parameters of the given function symbol. Only works for external functions.
/// \param parent The function symbol to get the parameter symbols for.
/// \return A list of function parameter symbols.
[[nodiscard]] ZKAPI std::vector<DaedalusSymbol const*>
[[nodiscard]] ZKAPI std::span<DaedalusSymbol const>
find_parameters_for_function(DaedalusSymbol const* parent) const;

/// \brief Retrieves the symbol with the given \p address set
Expand All @@ -825,7 +837,12 @@ namespace zenkit {
/// \brief Looks for parameters of the given function symbol. Only works for external functions.
/// \param parent The function symbol to get the parameter symbols for.
/// \return A list of function parameter symbols.
[[nodiscard]] ZKAPI std::vector<DaedalusSymbol*> find_parameters_for_function(DaedalusSymbol const* parent);
[[nodiscard]] ZKAPI std::span<DaedalusSymbol> find_parameters_for_function(DaedalusSymbol const* parent);

/// \brief Looks for local-variables of the given function symbol.
/// \param parent The function symbol to get the parameter symbols for.
/// \return A list of function local-variable symbols.
[[nodiscard]] ZKAPI std::span<DaedalusSymbol> find_locals_for_function(DaedalusSymbol const* parent);

/// \brief Retrieves the symbol with the given \p name.
/// \param name The name of the symbol to get.
Expand Down
57 changes: 34 additions & 23 deletions include/zenkit/DaedalusVm.hh
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ namespace zenkit {
throw DaedalusVmException {"Cannot call " + sym->name() + ": not a function"};
}

std::vector<DaedalusSymbol*> params = find_parameters_for_function(sym);
std::span<DaedalusSymbol> params = find_parameters_for_function(sym);
if (params.size() < sizeof...(P)) {
throw DaedalusVmException {"too many arguments provided for " + sym->name() + ": given " +
std::to_string(sizeof...(P)) + " expected " + std::to_string(params.size())};
Expand Down Expand Up @@ -439,7 +439,7 @@ namespace zenkit {
if (sym->has_return()) throw DaedalusIllegalExternalReturnType(sym, "void");
}

std::vector<DaedalusSymbol*> params = find_parameters_for_function(sym);
std::span<DaedalusSymbol> params = find_parameters_for_function(sym);
if (params.size() < sizeof...(P))
throw DaedalusIllegalExternalDefinition {sym,
"too many arguments declared for external " + sym->name() +
Expand Down Expand Up @@ -526,7 +526,7 @@ namespace zenkit {
if (sym->has_return()) throw DaedalusIllegalExternalReturnType(sym, "void");
}

std::vector<DaedalusSymbol*> params = find_parameters_for_function(sym);
std::span<DaedalusSymbol> params = find_parameters_for_function(sym);
if (params.size() < sizeof...(P))
throw DaedalusIllegalExternalDefinition {
sym,
Expand Down Expand Up @@ -714,12 +714,23 @@ namespace zenkit {
/// \param sym The symbol referring to the function called.
ZKINT void push_call(DaedalusSymbol const* sym);

/// \brief Pops a call stack from from the call stack.
/// \brief Pops a call stack frame from the call stack.
///
/// This method restores the interpreter's state to before the function which the
/// call stack entry refers to was called.
ZKINT void pop_call();

/// \brief Pushes a function local variables onto the call stack.
///
/// Part of #push_call implementation
/// \param sym The symbol referring to the function called.
ZKINT void push_local_variables(DaedalusSymbol const* sym);

/// \brief Pops a function-local variables from the call stack.
///
/// Part of #pop_call implementation
ZKINT void pop_local_variables(DaedalusSymbol const* sym);

/// \brief Checks that the type of each symbol in the given set of defined symbols matches the given type
/// parameters.
///
Expand All @@ -734,20 +745,20 @@ namespace zenkit {
/// \throws DaedalusIllegalExternalParameter If the types don't match.
/// \note Requires that sizeof...(Px) + 1 == defined.size().
template <int32_t i, typename P, typename... Px>
void check_external_params(std::vector<DaedalusSymbol*> const& defined) {
void check_external_params(std::span<DaedalusSymbol> const& defined) {
if constexpr (is_instance_ptr_v<P> || std::is_same_v<DaedalusSymbol*, P> || is_raw_instance_ptr_v<P>) {
if (defined[i]->type() != DaedalusDataType::INSTANCE)
throw DaedalusIllegalExternalParameter(defined[i], "instance", i + 1);
if (defined[i].type() != DaedalusDataType::INSTANCE)
throw DaedalusIllegalExternalParameter(&defined[i], "instance", i + 1);
} else if constexpr (std::is_same_v<float, P>) {
if (defined[i]->type() != DaedalusDataType::FLOAT)
throw DaedalusIllegalExternalParameter(defined[i], "float", i + 1);
if (defined[i].type() != DaedalusDataType::FLOAT)
throw DaedalusIllegalExternalParameter(&defined[i], "float", i + 1);
} else if constexpr (std::is_same_v<int32_t, P> || std::is_same_v<bool, P> ||
std::is_same_v<DaedalusFunction, P>) {
if (defined[i]->type() != DaedalusDataType::INT && defined[i]->type() != DaedalusDataType::FUNCTION)
throw DaedalusIllegalExternalParameter(defined[i], "int/func", i + 1);
if (defined[i].type() != DaedalusDataType::INT && defined[i].type() != DaedalusDataType::FUNCTION)
throw DaedalusIllegalExternalParameter(&defined[i], "int/func", i + 1);
} else if constexpr (std::is_same_v<std::string_view, P>) {
if (defined[i]->type() != DaedalusDataType::STRING)
throw DaedalusIllegalExternalParameter(defined[i], "string", i + 1);
if (defined[i].type() != DaedalusDataType::STRING)
throw DaedalusIllegalExternalParameter(&defined[i], "string", i + 1);
}

if constexpr (sizeof...(Px) > 0) {
Expand Down Expand Up @@ -916,25 +927,25 @@ namespace zenkit {
std::is_same_v<std::remove_reference_t<P>, std::string_view> ||
std::is_same_v<std::remove_reference_t<P>, DaedalusSymbol*>,
void>
push_call_parameters(std::vector<DaedalusSymbol*> const& defined, P value, Px... more) { // clang-format on
push_call_parameters(std::span<DaedalusSymbol> const& defined, P value, Px... more) { // clang-format on
if constexpr (is_instance_ptr_v<P> || std::is_same_v<DaedalusSymbol*, P>) {
if (defined[i]->type() != DaedalusDataType::INSTANCE)
throw DaedalusIllegalExternalParameter(defined[i], "instance", i + 1);
if (defined[i].type() != DaedalusDataType::INSTANCE)
throw DaedalusIllegalExternalParameter(&defined[i], "instance", i + 1);

push_instance(value);
} else if constexpr (std::is_same_v<float, P>) {
if (defined[i]->type() != DaedalusDataType::FLOAT)
throw DaedalusIllegalExternalParameter(defined[i], "float", i + 1);
if (defined[i].type() != DaedalusDataType::FLOAT)
throw DaedalusIllegalExternalParameter(&defined[i], "float", i + 1);

push_float(value);
} else if constexpr (std::is_same_v<int32_t, P> || std::is_same_v<bool, P>) {
if (defined[i]->type() != DaedalusDataType::INT && defined[i]->type() != DaedalusDataType::FUNCTION)
throw DaedalusIllegalExternalParameter(defined[i], "int", i + 1);
if (defined[i].type() != DaedalusDataType::INT && defined[i].type() != DaedalusDataType::FUNCTION)
throw DaedalusIllegalExternalParameter(&defined[i], "int", i + 1);

push_int(value);
} else if constexpr (std::is_same_v<std::string_view, P>) {
if (defined[i]->type() != DaedalusDataType::STRING)
throw DaedalusIllegalExternalParameter(defined[i], "string", i + 1);
if (defined[i].type() != DaedalusDataType::STRING)
throw DaedalusIllegalExternalParameter(&defined[i], "string", i + 1);

push_string(value);
}
Expand Down Expand Up @@ -983,7 +994,7 @@ namespace zenkit {
std::array<DaedalusStackFrame, stack_size> _m_stack;
uint16_t _m_stack_ptr {0};

std::stack<DaedalusCallStackFrame> _m_call_stack;
std::vector<DaedalusCallStackFrame> _m_call_stack;
std::unordered_map<DaedalusSymbol*, std::function<void(DaedalusVm&)>> _m_externals;
std::unordered_map<uint32_t, std::function<void(DaedalusVm&)>> _m_function_overrides;
std::optional<std::function<void(DaedalusVm&, DaedalusSymbol&)>> _m_default_external {std::nullopt};
Expand Down
41 changes: 25 additions & 16 deletions src/DaedalusScript.cc
Original file line number Diff line number Diff line change
Expand Up @@ -192,25 +192,27 @@ namespace zenkit {
}
}

std::vector<DaedalusSymbol*> DaedalusScript::find_parameters_for_function(DaedalusSymbol const* parent) {
std::vector<DaedalusSymbol*> syms {};

for (uint32_t i = 0; i < parent->count(); ++i) {
syms.push_back(find_symbol_by_index(parent->index() + i + 1));
std::span<DaedalusSymbol> DaedalusScript::find_parameters_for_function(DaedalusSymbol const* parent) {
return std::span<DaedalusSymbol>(_m_symbols.begin() + parent->index() + 1,
_m_symbols.begin() + parent->index() + parent->count() + 1);
}

std::span<DaedalusSymbol> DaedalusScript::find_locals_for_function(DaedalusSymbol const* parent) {
std::uint32_t const first = parent->index() + 1 + parent->count();
for (size_t i = first; i < _m_symbols.size(); ++i) {
auto& name = _m_symbols[i].name();
if (name.find(parent->name()) == 0 && name.size() >= parent->name().size() &&
name[parent->name().size()] == '.') {
continue;
}
return std::span<DaedalusSymbol>(_m_symbols.begin() + first, _m_symbols.begin() + i);
}

return syms;
return {};
}

std::vector<DaedalusSymbol const*>
DaedalusScript::find_parameters_for_function(DaedalusSymbol const* parent) const {
std::vector<DaedalusSymbol const*> syms {};

for (uint32_t i = 0; i < parent->count(); ++i) {
syms.push_back(find_symbol_by_index(parent->index() + i + 1));
}

return syms;
std::span<DaedalusSymbol const> DaedalusScript::find_parameters_for_function(DaedalusSymbol const* parent) const {
return std::span<DaedalusSymbol const>(_m_symbols.begin() + parent->index() + 1,
_m_symbols.begin() + parent->index() + parent->count() + 1);
}

std::vector<DaedalusSymbol*> DaedalusScript::find_class_members(DaedalusSymbol const& cls) {
Expand Down Expand Up @@ -610,6 +612,13 @@ namespace zenkit {
_m_flags &= ~DaedalusSymbolFlag::TRAP_ACCESS;
}

void zenkit::DaedalusSymbol::set_local_variables_enable(bool enable) noexcept {
if (enable)
_m_flags |= DaedalusSymbolFlag::FUNC_LOCALS;
else
_m_flags &= ~DaedalusSymbolFlag::FUNC_LOCALS;
}

DaedalusOpaqueInstance::DaedalusOpaqueInstance(DaedalusSymbol const& sym,
std::vector<DaedalusSymbol*> const& members) {
size_t str_count = 0;
Expand Down
Loading