#ifndef NONUT_CORE_FUNCTION_H #define NONUT_CORE_FUNCTION_H #include #include #include #include "Utils.h" #define FUNCTION_CTOR(function) function(#function) namespace nonut { class Class; template class Function { public: // Ctor for functions Function(const String& functionName, const SQObject env = getRootTable()) : envObj(env) { HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); sq_pushobject(vm, envObj); sq_pushstring(vm, functionName.c_str(), functionName.length()); // get the function from the root table if (SQ_FAILED(sq_get(vm, -2))) { sq_pop(vm, 1); throw; } // check the type if (const SQObjectType value_type = sq_gettype(vm, -1); value_type != OT_CLOSURE && value_type != OT_NATIVECLOSURE) { sq_pop(vm, 2); throw; } // get function and add ref sq_getstackobj(vm, -1, &funcObj); sq_addref(vm, &funcObj); sq_pop(vm, 2); } // Ctor for class methods Function(const String& functionName, const SQObject classObjectInstance, const SQObject classObject) : envObj(classObjectInstance) { HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); isClassMethod = true; // Prevent release of the resources cause we don't own them sq_pushobject(vm, classObject); sq_pushstring(vm, functionName.c_str(), functionName.length()); // get the function from the root table if (SQ_FAILED(sq_get(vm, -2))) { sq_pop(vm, 1); throw; } // check the type if (const SQObjectType value_type = sq_gettype(vm, -1); value_type != OT_CLOSURE && value_type != OT_NATIVECLOSURE) { sq_pop(vm, 2); throw; } // get function and add ref sq_getstackobj(vm, -1, &funcObj); sq_addref(vm, &funcObj); sq_pop(vm, 2); } ~Function() { if (!isClassMethod) { HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); sq_release(vm, &funcObj); sq_release(vm, &envObj); sq_resetobject(&funcObj); sq_resetobject(&envObj); } } ReturnType operator()(Args ... args) { HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); const auto top = sq_gettop(vm); sq_pushobject(vm, funcObj); sq_pushobject(vm, envObj); auto debug = sq_gettop(vm); (sqPushValue(vm, args), ...); if constexpr (std::is_same_v) { debug = sq_gettop(vm); auto returnCode = sq_call(vm, ARG_COUNT + 1, SQFalse, SQFalse); // TODO: HANDLE ERROR RETURN CODE sq_pop(vm, 2); sq_settop(vm, top); return void(); } else { auto returnCode = sq_call(vm, ARG_COUNT + 1, SQTrue, SQFalse); // TODO: HANDLE ERROR RETURN CODE std::optional result; if constexpr (std::derived_from) { result = std::make_optional(); auto intermediateResult = returnVar(); result.value().convert(intermediateResult); sq_release(vm, &intermediateResult); sq_resetobject(&intermediateResult); } else if constexpr (std::derived_from) { auto intermediateResult = returnVar(); //result = std::make_optional(ReturnType(intermediateResult)); result.emplace(ReturnType(intermediateResult)); sq_release(vm, &intermediateResult); sq_resetobject(&intermediateResult); } else { result = std::make_optional(returnVar()); } sq_pop(vm, 2); sq_settop(vm, top); return result.value(); } } [[nodiscard]] SQObject getObject() const { return funcObj; } private: SQObject funcObj{}; SQObject envObj{}; bool isClassMethod = false; static constexpr auto ARG_COUNT{sizeof...(Args)}; static SQObject getRootTable() { HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); SQObject rootTable{}; sq_pushroottable(vm); sq_getstackobj(vm, -1, &rootTable); sq_addref(vm, &rootTable); sq_pop(vm, 1); // pop root table return rootTable; } }; } #endif // NONUT_CORE_FUNCTION_H