Add coroutine support (WIP)

This commit is contained in:
Jérôme Leclercq 2017-06-08 15:53:17 +02:00
parent a8129b218b
commit 01edc4fb21
8 changed files with 154 additions and 16 deletions

View File

@ -0,0 +1,44 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Lua scripting module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_LUACOROUTINE_HPP
#define NAZARA_LUACOROUTINE_HPP
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Lua/LuaState.hpp>
#include <cstddef>
#include <functional>
namespace Nz
{
class NAZARA_LUA_API LuaCoroutine : public LuaState
{
friend class LuaState;
public:
LuaCoroutine(const LuaCoroutine&) = delete;
inline LuaCoroutine(LuaCoroutine&& instance);
~LuaCoroutine();
bool CanResume() const;
Ternary Resume(unsigned int argCount = 0);
LuaCoroutine& operator=(const LuaCoroutine&) = delete;
inline LuaCoroutine& operator=(LuaCoroutine&& instance);
private:
LuaCoroutine(lua_State* internalState, int refIndex);
bool Run(int argCount, int resultCount) override;
int m_ref;
};
}
#include <Nazara/Lua/LuaInstance.inl>
#endif // NAZARA_LUACOROUTINE_HPP

View File

@ -0,0 +1,25 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Lua scripting module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Lua/LuaCoroutine.hpp>
namespace Nz
{
inline LuaCoroutine::LuaCoroutine(LuaCoroutine&& instance) :
LuaState(std::move(instance)),
m_ref(instance.m_ref)
{
instance.m_ref = -1;
}
inline LuaCoroutine& LuaCoroutine::operator=(LuaCoroutine&& instance)
{
LuaState::operator=(std::move(instance));
m_ref = instance.m_ref;
instance.m_ref = -1;
return *this;
}
}

View File

@ -16,6 +16,7 @@ namespace Nz
{
class NAZARA_LUA_API LuaInstance : public LuaState
{
friend class LuaCoroutine;
friend class LuaState;
public:

View File

@ -21,6 +21,7 @@ struct lua_State;
namespace Nz
{
class LuaCoroutine;
class LuaInstance;
class LuaState;
@ -115,6 +116,7 @@ namespace Nz
void MoveTo(LuaState* instance, int n) const;
LuaCoroutine NewCoroutine();
bool NewMetatable(const char* str);
bool NewMetatable(const String& str);
bool Next(int index = -2) const;
@ -158,10 +160,8 @@ namespace Nz
void SetMetatable(const char* tname) const;
void SetMetatable(const String& tname) const;
void SetMetatable(int index) const;
void SetMemoryLimit(std::size_t memoryLimit);
void SetTable(int index = -3) const;
void SetTableRaw(int index = -3) const;
void SetTimeLimit(UInt32 timeLimit);
bool ToBoolean(int index) const;
long long ToInteger(int index, bool* succeeded = nullptr) const;
@ -176,18 +176,18 @@ namespace Nz
LuaState& operator=(LuaState&& instance) noexcept;
static int GetIndexOfUpValue(int upValue);
static LuaState GetState(lua_State* internalState);
static LuaInstance& GetInstance(lua_State* internalState);
static inline LuaState GetState(lua_State* internalState);
protected:
LuaState(LuaInstance* instance, lua_State* internalState);
LuaState(lua_State* internalState);
template<typename T> T CheckBounds(int index, long long value) const;
bool Run(int argCount, int resultCount);
virtual bool Run(int argCount, int resultCount);
static int ProxyFunc(lua_State* internalState);
String m_lastError;
LuaInstance* m_instance;
lua_State* m_state;
};
}

View File

@ -15,8 +15,7 @@
namespace Nz
{
inline LuaState::LuaState(LuaInstance* instance, lua_State* internalState) :
m_instance(instance),
inline LuaState::LuaState(lua_State* internalState) :
m_state(internalState)
{
}
@ -785,4 +784,9 @@ namespace Nz
return static_cast<T>(value);
}
inline LuaState LuaState::GetState(lua_State* internalState)
{
return LuaState(internalState);
}
}

View File

@ -0,0 +1,55 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Lua scripting module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Lua/LuaCoroutine.hpp>
#include <Lua/lauxlib.h>
#include <Lua/lua.h>
#include <Lua/lualib.h>
#include <Nazara/Lua/Debug.hpp>
namespace Nz
{
LuaCoroutine::LuaCoroutine(lua_State* internalState, int refIndex) :
LuaState(internalState),
m_ref(refIndex)
{
}
LuaCoroutine::~LuaCoroutine()
{
if (m_ref >= 0)
DestroyReference(m_ref);
}
bool LuaCoroutine::CanResume() const
{
return lua_status(m_state) == LUA_YIELD;
}
Ternary LuaCoroutine::Resume(unsigned int argCount)
{
LuaInstance& instance = GetInstance(m_state);
if (instance.m_level++ == 0)
instance.m_clock.Restart();
int status = lua_resume(m_state, nullptr, argCount);
instance.m_level--;
if (status == LUA_OK)
return Ternary_True;
else if (status == LUA_YIELD)
return Ternary_Unknown;
else
{
m_lastError = ToString(-1);
Pop();
return Ternary_False;
}
}
bool LuaCoroutine::Run(int argCount, int /*resultCount*/)
{
return Resume(argCount) != Ternary_False;
}
}

View File

@ -30,7 +30,7 @@ namespace Nz
}
LuaInstance::LuaInstance() :
LuaState(this, lua_newstate(MemoryAllocator, this)),
LuaState(nullptr),
m_memoryLimit(0),
m_memoryUsage(0),
m_timeLimit(1000),

View File

@ -12,6 +12,7 @@
#include <Nazara/Core/MemoryHelper.hpp>
#include <Nazara/Core/MemoryView.hpp>
#include <Nazara/Core/StringStream.hpp>
#include <Nazara/Lua/LuaCoroutine.hpp>
#include <Nazara/Lua/LuaInstance.hpp>
#include <cstdlib>
#include <stdexcept>
@ -127,7 +128,6 @@ namespace Nz
LuaState::LuaState(LuaState&& state) noexcept :
m_lastError(state.m_lastError),
m_instance(state.m_instance),
m_state(state.m_state)
{
}
@ -570,6 +570,14 @@ namespace Nz
lua_xmove(m_state, instance->m_state, n);
}
LuaCoroutine LuaState::NewCoroutine()
{
lua_State* thread = lua_newthread(m_state);
int ref = luaL_ref(m_state, LUA_REGISTRYINDEX);
return LuaCoroutine(thread, ref);
}
bool LuaState::NewMetatable(const char* str)
{
return luaL_newmetatable(m_state, str) != 0;
@ -783,7 +791,6 @@ namespace Nz
LuaState& LuaState::operator=(LuaState&& state) noexcept
{
m_instance = state.m_instance;
m_lastError = std::move(state.m_lastError);
m_state = state.m_state;
@ -792,12 +799,14 @@ namespace Nz
bool LuaState::Run(int argCount, int resultCount)
{
if (m_instance->m_level++ == 0)
m_instance->m_clock.Restart();
LuaInstance& instance = GetInstance(m_state);
if (instance.m_level++ == 0)
instance.m_clock.Restart();
int status = lua_pcall(m_state, argCount, resultCount, 0);
m_instance->m_level--;
instance.m_level--;
if (status != 0)
{
@ -815,12 +824,12 @@ namespace Nz
return lua_upvalueindex(upValue);
}
LuaState LuaState::GetState(lua_State* internalState)
LuaInstance& LuaState::GetInstance(lua_State* internalState)
{
LuaInstance* instance;
lua_getallocf(internalState, reinterpret_cast<void**>(&instance));
return LuaState(instance, internalState);
return *instance;
}
int LuaState::ProxyFunc(lua_State* internalState)