From fc24e0f2c4da129c678ff6d39ed60d1719918158 Mon Sep 17 00:00:00 2001 From: Try Date: Mon, 24 Nov 2025 23:55:13 +0100 Subject: [PATCH 01/11] [LeGo] add support for local variables #115 --- CMakeLists.txt | 2 +- include/zenkit/DaedalusScript.hh | 21 ++++- include/zenkit/DaedalusVm.hh | 57 +++++++------ src/DaedalusScript.cc | 36 +++++---- src/DaedalusVm.cc | 135 +++++++++++++++++++++++++++++-- 5 files changed, 203 insertions(+), 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e000ceb1..91826ebf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/include/zenkit/DaedalusScript.hh b/include/zenkit/DaedalusScript.hh index a5ce2cf8..f62f24bd 100644 --- a/include/zenkit/DaedalusScript.hh +++ b/include/zenkit/DaedalusScript.hh @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -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; @@ -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 { @@ -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; @@ -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 + [[nodiscard]] ZKAPI std::span find_parameters_for_function(DaedalusSymbol const* parent) const; /// \brief Retrieves the symbol with the given \p address set @@ -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 find_parameters_for_function(DaedalusSymbol const* parent); + [[nodiscard]] ZKAPI std::span 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 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. diff --git a/include/zenkit/DaedalusVm.hh b/include/zenkit/DaedalusVm.hh index 96f0d4b7..87894c23 100644 --- a/include/zenkit/DaedalusVm.hh +++ b/include/zenkit/DaedalusVm.hh @@ -132,7 +132,7 @@ namespace zenkit { throw DaedalusVmException {"Cannot call " + sym->name() + ": not a function"}; } - std::vector params = find_parameters_for_function(sym); + std::span 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())}; @@ -439,7 +439,7 @@ namespace zenkit { if (sym->has_return()) throw DaedalusIllegalExternalReturnType(sym, "void"); } - std::vector params = find_parameters_for_function(sym); + std::span params = find_parameters_for_function(sym); if (params.size() < sizeof...(P)) throw DaedalusIllegalExternalDefinition {sym, "too many arguments declared for external " + sym->name() + @@ -526,7 +526,7 @@ namespace zenkit { if (sym->has_return()) throw DaedalusIllegalExternalReturnType(sym, "void"); } - std::vector params = find_parameters_for_function(sym); + std::span params = find_parameters_for_function(sym); if (params.size() < sizeof...(P)) throw DaedalusIllegalExternalDefinition { sym, @@ -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. /// @@ -734,20 +745,20 @@ namespace zenkit { /// \throws DaedalusIllegalExternalParameter If the types don't match. /// \note Requires that sizeof...(Px) + 1 == defined.size(). template - void check_external_params(std::vector const& defined) { + void check_external_params(std::span const& defined) { if constexpr (is_instance_ptr_v

|| std::is_same_v || is_raw_instance_ptr_v

) { - 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) { - 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 || std::is_same_v || std::is_same_v) { - 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) { - 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) { @@ -916,25 +927,25 @@ namespace zenkit { std::is_same_v, std::string_view> || std::is_same_v, DaedalusSymbol*>, void> - push_call_parameters(std::vector const& defined, P value, Px... more) { // clang-format on + push_call_parameters(std::span const& defined, P value, Px... more) { // clang-format on if constexpr (is_instance_ptr_v

|| std::is_same_v) { - 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) { - 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 || std::is_same_v) { - 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) { - 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); } @@ -983,7 +994,7 @@ namespace zenkit { std::array _m_stack; uint16_t _m_stack_ptr {0}; - std::stack _m_call_stack; + std::vector _m_call_stack; std::unordered_map> _m_externals; std::unordered_map> _m_function_overrides; std::optional> _m_default_external {std::nullopt}; diff --git a/src/DaedalusScript.cc b/src/DaedalusScript.cc index aa3bfda2..8030e5c3 100644 --- a/src/DaedalusScript.cc +++ b/src/DaedalusScript.cc @@ -192,25 +192,24 @@ namespace zenkit { } } - std::vector DaedalusScript::find_parameters_for_function(DaedalusSymbol const* parent) { - std::vector 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 DaedalusScript::find_parameters_for_function(DaedalusSymbol const* parent) { + return std::span(_m_symbols.begin() + parent->index() + 1, _m_symbols.begin() + parent->index() + parent->count() + 1); } - std::vector - DaedalusScript::find_parameters_for_function(DaedalusSymbol const* parent) const { - std::vector syms {}; - - for (uint32_t i = 0; i < parent->count(); ++i) { - syms.push_back(find_symbol_by_index(parent->index() + i + 1)); + std::span DaedalusScript::find_locals_for_function(DaedalusSymbol const* parent) { + const std::uint32_t 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(_m_symbols.begin() + first, _m_symbols.begin() + i); + } + return {}; } - return syms; + std::span DaedalusScript::find_parameters_for_function(DaedalusSymbol const* parent) const { + return std::span(_m_symbols.begin() + parent->index() + 1, _m_symbols.begin() + parent->index() + parent->count() + 1); } std::vector DaedalusScript::find_class_members(DaedalusSymbol const& cls) { @@ -610,6 +609,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 const& members) { size_t str_count = 0; diff --git a/src/DaedalusVm.cc b/src/DaedalusVm.cc index 263dfeaa..ab6186a6 100644 --- a/src/DaedalusVm.cc +++ b/src/DaedalusVm.cc @@ -455,12 +455,15 @@ namespace zenkit { } void DaedalusVm::push_call(DaedalusSymbol const* sym) { + if(sym->has_local_variables_enabled()) { + push_local_variables(sym); + } auto var_count = this->find_parameters_for_function(sym).size(); - _m_call_stack.push({sym, _m_pc, _m_stack_ptr - static_cast(var_count), _m_instance}); + _m_call_stack.push_back({sym, _m_pc, _m_stack_ptr - static_cast(var_count), _m_instance}); } void DaedalusVm::pop_call() { - auto const& call = _m_call_stack.top(); + auto const& call = _m_call_stack.back(); // First, try to fix up the stack. if (!call.function->has_return()) { @@ -487,10 +490,128 @@ namespace zenkit { // } } + if(call.function->has_local_variables_enabled()) { + pop_local_variables(call.function); + } + // Second, reset PC and context, then remove the call stack frame _m_pc = call.program_counter; _m_instance = call.context; - _m_call_stack.pop(); + _m_call_stack.pop_back(); + } + + void DaedalusVm::push_local_variables(DaedalusSymbol const* sym) { + bool has_recursion = false; + for(auto& i:_m_call_stack) + if(i.function==sym) { + has_recursion = true; + break; + } + if(!has_recursion) + return; + + auto params = this->find_parameters_for_function(sym); + auto locals = this->find_locals_for_function(sym); + + if (_m_stack_ptr+locals.size() > stack_size) { + throw DaedalusVmException {"stack overflow"}; + } + + if (_m_stack_ptrhas_return()) { + ret = std::move(_m_stack[--_m_stack_ptr]); + } + + auto locals = this->find_locals_for_function(sym); + for(size_t i=locals.size(); i>0;) { + --i; + auto& l = locals[i]; + switch (l.type()) { + case DaedalusDataType::VOID: + break; + case DaedalusDataType::FLOAT: + for(std::uint32_t r=l.count(); r>0; ) { + --r; + l.set_float(pop_float(), r); + } + break; + case DaedalusDataType::FUNCTION: + case DaedalusDataType::INT: + for(std::uint32_t r=l.count(); r>0; ) { + --r; + l.set_int(pop_int(), r); + } + break; + case DaedalusDataType::STRING: + for(std::uint32_t r=l.count(); r>0; ) { + --r; + l.set_string(pop_string(), r); + } + break; + case DaedalusDataType::INSTANCE: + l.set_instance(pop_instance()); + break; + case DaedalusDataType::CLASS: + case DaedalusDataType::PROTOTYPE: + throw DaedalusVmException {"unexpected"}; + break; + } + } + + if(sym->has_return()) { + _m_stack[_m_stack_ptr++] = std::move(ret); + } } void DaedalusVm::push_int(std::int32_t value) { @@ -661,12 +782,12 @@ namespace zenkit { // pop all parameters from the stack auto params = find_parameters_for_function(&sym); for (int i = static_cast(params.size()) - 1; i >= 0; --i) { - auto par = params[static_cast(i)]; - if (par->type() == DaedalusDataType::INT) + auto& par = params[static_cast(i)]; + if (par.type() == DaedalusDataType::INT) (void) v.pop_int(); - else if (par->type() == DaedalusDataType::FLOAT) + else if (par.type() == DaedalusDataType::FLOAT) (void) v.pop_float(); - else if (par->type() == DaedalusDataType::INSTANCE || par->type() == DaedalusDataType::STRING) + else if (par.type() == DaedalusDataType::INSTANCE || par.type() == DaedalusDataType::STRING) (void) v.pop_reference(); } From 39ea21ac92f21a713a15b4795b2b3c750660d3ac Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 25 Nov 2025 00:24:20 +0100 Subject: [PATCH 02/11] fixup estimation of stack storage for arrayed variables --- src/DaedalusVm.cc | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/DaedalusVm.cc b/src/DaedalusVm.cc index ab6186a6..155d95d0 100644 --- a/src/DaedalusVm.cc +++ b/src/DaedalusVm.cc @@ -513,7 +513,28 @@ namespace zenkit { auto params = this->find_parameters_for_function(sym); auto locals = this->find_locals_for_function(sym); - if (_m_stack_ptr+locals.size() > stack_size) { + // estimate stack storage for local copy of variables + std::uint32_t locals_size = 0; + for(auto& l:locals) { + switch (l.type()) { + case DaedalusDataType::VOID: + break; + case DaedalusDataType::FLOAT: + case DaedalusDataType::FUNCTION: + case DaedalusDataType::INT: + case DaedalusDataType::STRING: + locals_size += l.count(); + break; + case DaedalusDataType::INSTANCE: + locals_size += 1; + break; + case DaedalusDataType::CLASS: + case DaedalusDataType::PROTOTYPE: + break; + } + } + + if (_m_stack_ptr+locals_size > stack_size) { throw DaedalusVmException {"stack overflow"}; } @@ -524,7 +545,7 @@ namespace zenkit { // move function arguments futher _m_stack_ptr -= params.size(); for(size_t i=0; i Date: Tue, 25 Nov 2025 00:34:54 +0100 Subject: [PATCH 03/11] code-style --- src/DaedalusScript.cc | 10 +++++----- src/DaedalusVm.cc | 37 +++++++++++++++++++------------------ 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/DaedalusScript.cc b/src/DaedalusScript.cc index 8030e5c3..9e51ab3c 100644 --- a/src/DaedalusScript.cc +++ b/src/DaedalusScript.cc @@ -198,18 +198,18 @@ namespace zenkit { std::span DaedalusScript::find_locals_for_function(DaedalusSymbol const* parent) { const std::uint32_t first = parent->index() + 1 + parent->count(); - for (size_t i = first; i<_m_symbols.size(); ++i) { + 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()]=='.') { + if(name.find(parent->name()) == 0 && name.size() >= parent->name().size() && name[parent->name().size()] == '.') { continue; } return std::span(_m_symbols.begin() + first, _m_symbols.begin() + i); } return {}; - } + } - std::span DaedalusScript::find_parameters_for_function(DaedalusSymbol const* parent) const { - return std::span(_m_symbols.begin() + parent->index() + 1, _m_symbols.begin() + parent->index() + parent->count() + 1); + std::span DaedalusScript::find_parameters_for_function(DaedalusSymbol const* parent) const { + return std::span(_m_symbols.begin() + parent->index() + 1, _m_symbols.begin() + parent->index() + parent->count() + 1); } std::vector DaedalusScript::find_class_members(DaedalusSymbol const& cls) { diff --git a/src/DaedalusVm.cc b/src/DaedalusVm.cc index 155d95d0..026b2679 100644 --- a/src/DaedalusVm.cc +++ b/src/DaedalusVm.cc @@ -455,7 +455,7 @@ namespace zenkit { } void DaedalusVm::push_call(DaedalusSymbol const* sym) { - if(sym->has_local_variables_enabled()) { + if (sym->has_local_variables_enabled()) { push_local_variables(sym); } auto var_count = this->find_parameters_for_function(sym).size(); @@ -491,6 +491,7 @@ namespace zenkit { } if(call.function->has_local_variables_enabled()) { + if (call.function->has_local_variables_enabled()) { pop_local_variables(call.function); } @@ -503,11 +504,11 @@ namespace zenkit { void DaedalusVm::push_local_variables(DaedalusSymbol const* sym) { bool has_recursion = false; for(auto& i:_m_call_stack) - if(i.function==sym) { + for (auto& i:_m_call_stack) has_recursion = true; break; } - if(!has_recursion) + if (!has_recursion) return; auto params = this->find_parameters_for_function(sym); @@ -515,7 +516,7 @@ namespace zenkit { // estimate stack storage for local copy of variables std::uint32_t locals_size = 0; - for(auto& l:locals) { + for (auto& l:locals) { switch (l.type()) { case DaedalusDataType::VOID: break; @@ -544,27 +545,27 @@ namespace zenkit { // move function arguments futher _m_stack_ptr -= params.size(); - for(size_t i=0; ihas_return()) { + if (sym->has_return()) { ret = std::move(_m_stack[--_m_stack_ptr]); } @@ -602,20 +603,20 @@ namespace zenkit { case DaedalusDataType::VOID: break; case DaedalusDataType::FLOAT: - for(std::uint32_t r=l.count(); r>0; ) { + for (std::uint32_t r=l.count(); r>0; ) { --r; l.set_float(pop_float(), r); } break; case DaedalusDataType::FUNCTION: case DaedalusDataType::INT: - for(std::uint32_t r=l.count(); r>0; ) { + for (std::uint32_t r = l.count(); r>0; ) { --r; l.set_int(pop_int(), r); } break; case DaedalusDataType::STRING: - for(std::uint32_t r=l.count(); r>0; ) { + for (std::uint32_t r = l.count(); r>0; ) { --r; l.set_string(pop_string(), r); } @@ -630,7 +631,7 @@ namespace zenkit { } } - if(sym->has_return()) { + if (sym->has_return()) { _m_stack[_m_stack_ptr++] = std::move(ret); } } From 28ccb2c197dde2b9b4601d5d4f13fd9ec5bfd022 Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 25 Nov 2025 00:45:25 +0100 Subject: [PATCH 04/11] CI --- src/DaedalusVm.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/DaedalusVm.cc b/src/DaedalusVm.cc index 026b2679..9617d934 100644 --- a/src/DaedalusVm.cc +++ b/src/DaedalusVm.cc @@ -490,7 +490,6 @@ namespace zenkit { // } } - if(call.function->has_local_variables_enabled()) { if (call.function->has_local_variables_enabled()) { pop_local_variables(call.function); } @@ -503,8 +502,8 @@ namespace zenkit { void DaedalusVm::push_local_variables(DaedalusSymbol const* sym) { bool has_recursion = false; - for(auto& i:_m_call_stack) for (auto& i:_m_call_stack) + if (i.function == sym) { has_recursion = true; break; } @@ -596,7 +595,7 @@ namespace zenkit { } auto locals = this->find_locals_for_function(sym); - for(size_t i=locals.size(); i>0;) { + for (size_t i = locals.size(); i > 0;) { --i; auto& l = locals[i]; switch (l.type()) { From 4967976349ea7b9bd50c45ee4d7032c8c6aa496b Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 25 Nov 2025 00:51:05 +0100 Subject: [PATCH 05/11] format --- src/DaedalusScript.cc | 2 +- src/DaedalusVm.cc | 23 +++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/DaedalusScript.cc b/src/DaedalusScript.cc index 9e51ab3c..9ed169cc 100644 --- a/src/DaedalusScript.cc +++ b/src/DaedalusScript.cc @@ -200,7 +200,7 @@ namespace zenkit { const std::uint32_t 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()] == '.') { + if (name.find(parent->name()) == 0 && (name.size() >= parent->name().size()) && name[parent->name().size()] == '.') { continue; } return std::span(_m_symbols.begin() + first, _m_symbols.begin() + i); diff --git a/src/DaedalusVm.cc b/src/DaedalusVm.cc index 9617d934..cf5061df 100644 --- a/src/DaedalusVm.cc +++ b/src/DaedalusVm.cc @@ -502,20 +502,21 @@ namespace zenkit { void DaedalusVm::push_local_variables(DaedalusSymbol const* sym) { bool has_recursion = false; - for (auto& i:_m_call_stack) + for (auto& i : _m_call_stack) if (i.function == sym) { has_recursion = true; break; } - if (!has_recursion) + if (!has_recursion) { return; + } auto params = this->find_parameters_for_function(sym); auto locals = this->find_locals_for_function(sym); // estimate stack storage for local copy of variables std::uint32_t locals_size = 0; - for (auto& l:locals) { + for (auto& l : locals) { switch (l.type()) { case DaedalusDataType::VOID: break; @@ -534,11 +535,11 @@ namespace zenkit { } } - if (_m_stack_ptr+locals_size > stack_size) { + if (_m_stack_ptr + locals_size > stack_size) { throw DaedalusVmException {"stack overflow"}; } - if (_m_stack_ptrhas_return()) { @@ -602,7 +604,7 @@ namespace zenkit { case DaedalusDataType::VOID: break; case DaedalusDataType::FLOAT: - for (std::uint32_t r=l.count(); r>0; ) { + for (std::uint32_t r = l.count(); r>0; ) { --r; l.set_float(pop_float(), r); } @@ -620,8 +622,9 @@ namespace zenkit { l.set_string(pop_string(), r); } break; - case DaedalusDataType::INSTANCE: + case DaedalusDataType::INSTANCE: { l.set_instance(pop_instance()); + } break; case DaedalusDataType::CLASS: case DaedalusDataType::PROTOTYPE: From 4021beab87325c6cc8136bd553f1f6014f7032e5 Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 25 Nov 2025 01:02:11 +0100 Subject: [PATCH 06/11] format --- src/DaedalusVm.cc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/DaedalusVm.cc b/src/DaedalusVm.cc index cf5061df..eec3851f 100644 --- a/src/DaedalusVm.cc +++ b/src/DaedalusVm.cc @@ -516,7 +516,7 @@ namespace zenkit { // estimate stack storage for local copy of variables std::uint32_t locals_size = 0; - for (auto& l : locals) { + for (auto& l : locals) { switch (l.type()) { case DaedalusDataType::VOID: break; @@ -604,28 +604,27 @@ namespace zenkit { case DaedalusDataType::VOID: break; case DaedalusDataType::FLOAT: - for (std::uint32_t r = l.count(); r>0; ) { + for (std::uint32_t r = l.count(); r > 0; ) { --r; l.set_float(pop_float(), r); } break; case DaedalusDataType::FUNCTION: case DaedalusDataType::INT: - for (std::uint32_t r = l.count(); r>0; ) { + for (std::uint32_t r = l.count(); r > 0; ) { --r; l.set_int(pop_int(), r); } break; case DaedalusDataType::STRING: - for (std::uint32_t r = l.count(); r>0; ) { + for (std::uint32_t r = l.count(); r > 0; ) { --r; l.set_string(pop_string(), r); } break; - case DaedalusDataType::INSTANCE: { + case DaedalusDataType::INSTANCE: l.set_instance(pop_instance()); - } - break; + break; case DaedalusDataType::CLASS: case DaedalusDataType::PROTOTYPE: throw DaedalusVmException {"unexpected"}; From ac876342bc7d878cfac775c8769e335263c34e35 Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 25 Nov 2025 01:28:17 +0100 Subject: [PATCH 07/11] format --- src/DaedalusVm.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/DaedalusVm.cc b/src/DaedalusVm.cc index eec3851f..08428029 100644 --- a/src/DaedalusVm.cc +++ b/src/DaedalusVm.cc @@ -604,20 +604,20 @@ namespace zenkit { case DaedalusDataType::VOID: break; case DaedalusDataType::FLOAT: - for (std::uint32_t r = l.count(); r > 0; ) { + for (std::uint32_t r = l.count(); r > 0;) { --r; l.set_float(pop_float(), r); } break; case DaedalusDataType::FUNCTION: case DaedalusDataType::INT: - for (std::uint32_t r = l.count(); r > 0; ) { + for (std::uint32_t r = l.count(); r > 0;) { --r; l.set_int(pop_int(), r); } break; case DaedalusDataType::STRING: - for (std::uint32_t r = l.count(); r > 0; ) { + for (std::uint32_t r = l.count(); r > 0;) { --r; l.set_string(pop_string(), r); } From d6d177216b467759cc2941be093e1de96ea5b61c Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 25 Nov 2025 01:33:04 +0100 Subject: [PATCH 08/11] format --- src/DaedalusScript.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/DaedalusScript.cc b/src/DaedalusScript.cc index 9ed169cc..e4eff648 100644 --- a/src/DaedalusScript.cc +++ b/src/DaedalusScript.cc @@ -197,10 +197,11 @@ namespace zenkit { } std::span DaedalusScript::find_locals_for_function(DaedalusSymbol const* parent) { - const std::uint32_t first = parent->index() + 1 + parent->count(); + 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()] == '.') { + if (name.find(parent->name()) == 0 && (name.size() >= parent->name().size()) && + name[parent->name().size()] == '.') { continue; } return std::span(_m_symbols.begin() + first, _m_symbols.begin() + i); @@ -209,7 +210,8 @@ namespace zenkit { } std::span DaedalusScript::find_parameters_for_function(DaedalusSymbol const* parent) const { - return std::span(_m_symbols.begin() + parent->index() + 1, _m_symbols.begin() + parent->index() + parent->count() + 1); + return std::span(_m_symbols.begin() + parent->index() + 1, + _m_symbols.begin() + parent->index() + parent->count() + 1); } std::vector DaedalusScript::find_class_members(DaedalusSymbol const& cls) { From 0e89a736bb579d736be1c6c673f43565d6fc470d Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 25 Nov 2025 01:35:07 +0100 Subject: [PATCH 09/11] format --- src/DaedalusScript.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DaedalusScript.cc b/src/DaedalusScript.cc index e4eff648..bb1e02b2 100644 --- a/src/DaedalusScript.cc +++ b/src/DaedalusScript.cc @@ -201,7 +201,7 @@ namespace zenkit { 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()] == '.') { + name[parent->name().size()] == '.') { continue; } return std::span(_m_symbols.begin() + first, _m_symbols.begin() + i); From d7cb59fc49649c7d9ec388e351da2cc26d0f5b38 Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 25 Nov 2025 01:38:24 +0100 Subject: [PATCH 10/11] format --- src/DaedalusScript.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/DaedalusScript.cc b/src/DaedalusScript.cc index bb1e02b2..f40ae33d 100644 --- a/src/DaedalusScript.cc +++ b/src/DaedalusScript.cc @@ -193,14 +193,15 @@ namespace zenkit { } std::span DaedalusScript::find_parameters_for_function(DaedalusSymbol const* parent) { - return std::span(_m_symbols.begin() + parent->index() + 1, _m_symbols.begin() + parent->index() + parent->count() + 1); + return std::span(_m_symbols.begin() + parent->index() + 1, + _m_symbols.begin() + parent->index() + parent->count() + 1); } std::span 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()) && + if (name.find(parent->name()) == 0 && name.size() >= parent->name().size() && name[parent->name().size()] == '.') { continue; } From 495d77d93a9c870002f977858802c85bc96b61b9 Mon Sep 17 00:00:00 2001 From: Luis Michaelis Date: Sun, 30 Nov 2025 09:42:00 +0100 Subject: [PATCH 11/11] chore: code-style and short explanation --- src/DaedalusVm.cc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/DaedalusVm.cc b/src/DaedalusVm.cc index 08428029..0b4420ee 100644 --- a/src/DaedalusVm.cc +++ b/src/DaedalusVm.cc @@ -502,11 +502,13 @@ namespace zenkit { void DaedalusVm::push_local_variables(DaedalusSymbol const* sym) { bool has_recursion = false; - for (auto& i : _m_call_stack) + for (auto& i : _m_call_stack) { if (i.function == sym) { has_recursion = true; break; } + } + if (!has_recursion) { return; } @@ -543,7 +545,8 @@ namespace zenkit { throw DaedalusVmException {"stack underoverflow"}; } - // move function arguments futher + // Move function arguments further back, since we're currently at the call instruction and the + // arguments for the next call have already been pushed. _m_stack_ptr -= params.size(); for (size_t i = 0; i < params.size(); ++i) { _m_stack[_m_stack_ptr + locals_size + i] = std::move(_m_stack[_m_stack_ptr + i]); @@ -574,19 +577,22 @@ namespace zenkit { break; case DaedalusDataType::CLASS: case DaedalusDataType::PROTOTYPE: - throw DaedalusVmException {"unexpected"}; + ZKLOGW("DaedalusVm", "Attempted to save class or prototype in stack frame"); break; } } + _m_stack_ptr += params.size(); } void DaedalusVm::pop_local_variables(DaedalusSymbol const* sym) { int has_recursion = 0; - for (auto& i : _m_call_stack) + for (auto& i : _m_call_stack) { if (i.function == sym) { ++has_recursion; } + } + if (has_recursion <= 1) { return; } @@ -627,7 +633,7 @@ namespace zenkit { break; case DaedalusDataType::CLASS: case DaedalusDataType::PROTOTYPE: - throw DaedalusVmException {"unexpected"}; + ZKLOGW("DaedalusVm", "Attempted to restore class or prototype in stack frame"); break; } }