UniqueLuaReference::UniqueLuaReference(lua_State* state, int reference) : _luaState(state), _reference(reference) { if (state == nullptr) { throw LuaException("Need a valid lua state!"); } if (reference < 0) { throw LuaException("Reference must be greater than or equal to zero!"); } }
static void initialize(LuaStack& stack, rainback::protocol::AbstractLine& ptl) { lua::push(stack, lua::value::table); auto methods = stack.saveAndPop(); methods["listen"] = std::function<void(LuaStack&)>( [](LuaStack& stack) { rainback::protocol::AbstractLine& ptl = stack.as<rainback::protocol::AbstractLine&>(1); auto socket = stack.as<QAbstractSocket*>(2); if (!socket) { throw LuaException("A socket or other IO device must be provided"); } // Introduce a reference visible from Lua to ensure the socket doesn't get prematurely GC'd auto worker = stack.lua()("" "return function(proto, socket)\n" " proto.__extra.io = socket;\n" "end;" ); lua::push(stack, worker); stack.insert(1); stack.pushedInvoke(2); ptl.listen(socket); stack.clear(); } ); methods["write"] = std::function<void(rainback::protocol::AbstractLine&, const QString&)>( [](rainback::protocol::AbstractLine& ptl, const QString& data) { if (!ptl.io()) { throw LuaException("Write must have a socket or IO device to write to"); } auto io = ptl.io(); if (!io->isOpen()) { throw LuaException("Write cannot write to a closed socket or IO device"); } if (qobject_cast<QAbstractSocket*>(io)) { auto socket = qobject_cast<QAbstractSocket*>(io); if (socket->state() != QAbstractSocket::ConnectedState) { std::stringstream str; str << "Write cannot write to an unconnected socket. Current state was "; str << rainback::proxy::getSocketStateName(socket->state()); throw LuaException(str.str()); } } ptl.write(data); } ); rainback::proxy::wrapQObject(stack, ptl, methods); rainback::proxy::observeToDestroy(stack, ptl, true); }
std::string Lua::CallFunction(std::string functionName, LuaFunctionArguments arguments) { if(!m_isLoaded) throw LuaException("Lua engine not loaded, use Load() first."); lua_getglobal(m_lua, functionName.c_str()); //If function not found return empty string if(!lua_isfunction(m_lua, -1)) { return ""; } //Pass all arguments to function for(size_t argc=0; argc<arguments.Count(); argc++) { switch(arguments[argc].type) { case BOOL: lua_pushboolean(m_lua, arguments[argc].value.BVAL); break; case INTEGER: lua_pushinteger(m_lua, arguments[argc].value.IVAL); break; case STRING: lua_pushstring(m_lua, arguments[argc].value.SVAL); break; case DOUBLE: lua_pushnumber(m_lua, arguments[argc].value.DVAL); break; } } /* do the call (arguments count, 1 result) */ if (lua_pcall(m_lua, arguments.Count(), 1, 0) != 0) { std::string errorMessage = "Error on function: "; errorMessage += functionName; errorMessage += "()"; throw LuaException(errorMessage); } return lua_tostring(m_lua, -1); }
//~~<<luaengine_die void LuaGameEngine::dieIfFail(int state) const { if (state) { const char *err = lua_tostring(L, -1); throw LuaException(err); } }
void pushValue(lua_State* luaState, const LuaValue& value) { if (luaState != value.getLuaState()) { throw LuaException("Lua state mismatch!"); } value.pushValue(); }
void LuaInterface::loadBuffer(const std::string& buffer, const std::string& source) { // loads lua buffer int ret = luaL_loadbuffer(L, buffer.c_str(), buffer.length(), source.c_str()); if(ret != 0) throw LuaException(popString(), 0); }
int LuaInterface::safeCall(int numArgs, int numRets) { assert(hasIndex(-numArgs-1)); // saves the current stack size for calculating the number of results later int previousStackSize = stackSize(); // pushes error function int errorFuncIndex = previousStackSize - numArgs; pushCFunction(&LuaInterface::luaErrorHandler); insert(errorFuncIndex); // calls the function in protected mode (means errors will be caught) int ret = pcall(numArgs, LUA_MULTRET, errorFuncIndex); remove(errorFuncIndex); // remove error func // if there was an error throw an exception if(ret != 0) throw LuaException(popString()); int rets = (stackSize() + numArgs + 1) - previousStackSize; while(numRets != -1 && rets != numRets) { if(rets < numRets) { pushNil(); rets++; } else { pop(); rets--; } } // returns the number of results return rets; }
LuaFunction LuaFunction::createFromCode(lua_State* L, std::string const& code, std::string const& name) { int err = luaL_loadbuffer(L, code.c_str(), code.length(), name.c_str()); if (!err) { LuaFunction func; func.setReference(LuaReference::create(L)); lua_pop(L, 1); return func; } else { // Get the error message size_t len; const char* err = lua_tolstring(L, -1, &len); lua_pop(L, 1); throw LuaException(std::string(err, len)); } }
void Interpreter::pushUserType(void *data, const std::string& type) { int top = getTop(); tolua_pushusertype(luastate,data,type.c_str()); if (getTop() == top) throw LuaException(std::string("Failed to push user type ") + type); }
T getTableField(lua_State* L, std::string const& name) { std::string::size_type startPos = 0; std::string::size_type endPos = name.find(".", startPos); std::size_t stackCount = 0; T ret; if (std::string::npos == endPos) { lua_getglobal(L, name.c_str()); ret = getFromStack<T>(L); lua_pop(L, 1); return ret; } lua_getglobal(L, name.substr(startPos, endPos - startPos).c_str()); startPos = endPos + 1; ++stackCount; while (std::string::npos != (endPos = name.find(".", startPos))) { std::string tableName = name.substr(startPos, endPos - startPos); if (!lua_istable(L, -1)) { lua_pop(L, stackCount); throw LuaException("Invalid variable " + name); } lua_getfield(L, -1, tableName.c_str()); ++stackCount; startPos = endPos + 1; } if (!lua_istable(L, -1)) { lua_pop(L, stackCount); throw LuaException("Invalid variable " + name); } lua_getfield(L, -1, name.substr(startPos).c_str()); ++stackCount; ret = getFromStack<T>(L); lua_pop(L, stackCount); return ret; }
void Interpreter::pop(const int num) { if (num > getTop()) { std::cout << "woah... num " << num << " top " << getTop() << ", stack:\n" << getStack(); throw LuaException("Attempt to pop more than what is on the stack\n" + getStack()); } lua_pop(luastate, num); }
void LuaWrapper::doString(const string& lua){ if( !script ) raise(LuaException,"Lua not initialized!"); try{ script->doString(lua.c_str()); }catch(exception& e){ throw LuaException(e.what()); } }
void LuaWrapper::doFile(const string& fileName){ if( !script ) raise(LuaException,"Lua not initialized!"); try{ script->doFile(fileName.c_str()); }catch(exception& e){ throw LuaException(e.what()); } }
LuaReference UniqueLuaReference::create(lua_State* state, int position) { if (state == nullptr) { throw LuaException("Need a valid lua state!"); } lua_pushvalue(state, position); LuaReference ref(new UniqueLuaReference(state, luaL_ref(state, LUA_REGISTRYINDEX))); return ref; }
void Context::runLuaScript( const std::string &str ) { if(luaL_dostring(mState->getLuaState(), str.c_str()) != 0){ throw LuaException( lua_tostring(mState->getLuaState(), -1) ); } ///collect garbage lua_gc(mState->getLuaState(), LUA_GCCOLLECT, 0); }
State::State( Context* context_name ):mContext(context_name){ mState = luaL_newstate(); if(!mState){ throw LuaException( "Error creating state for context: " + mContext->getName() ); } luaL_openlibs( mState ); luabind::open( mState ); lua_atpanic(mState, &State::panic); luabind::set_pcall_callback(&defaultLuabindErrorHandler); }
T getFromStack(lua_State* L) { std::string ret; if (!lua_isnil(L, -1)) { ret = lua_tostring(L, -1); } else { throw LuaException("Value on the stack is nil"); } return ret; }
void Lua::pcallWrapper(int nargs, int nresults, const char *name) { int result = lua_pcall(L, nargs, nresults, 0); if (result != 0) { std::stringstream buf; if (result == LUA_ERRRUN) { buf << "Error while calling " << name << std::endl << lua_tostring(L, -1); } else { buf << "Out of memory or unknown error while calling " << name; } throw LuaException(buf.str().c_str()); } }
void validatePort(const int port) { if (port > 0 && port <= USHRT_MAX) { return; } std::stringstream str; if (port < 0) { str << "Port must be greater than zero, but was given " << port; } else if (port > USHRT_MAX) { str << "Port must be less than " << USHRT_MAX << ", but was given " << port; } throw LuaException(str.str()); }
void LuaTable::setReference(const LuaReference& ref) { ref->pushValue(); lua_State* L = ref->getState(); if (lua_type(L, -1) != LUA_TTABLE) { lua_pop(L, 1); throw LuaException("Reference does not refere to a table!"); } else { lua_pop(L, 1); LuaValue::setReference(ref); } }
void LuaFunction::setReference(LuaReference ref) { ref->pushValue(); lua_State* L = ref->getState(); if (lua_type(L, -1) != LUA_TFUNCTION) { lua_pop(L, 1); throw LuaException("Reference does not refere to a function!"); } else { lua_pop(L, 1); LuaValue::setReference(ref); } }
bool LuaTable::setMetatable(const LuaTable& table) { if (!table.getReference()->isValid()) { throw LuaException("Meta table reference is not valid!"); } this->pushValue(); table.pushValue(); lua_setmetatable(_luaState, -2); lua_pop(_luaState, 1); return true; }
bool LuaFunction::setEnvironment(const LuaTable& table) { if (!table.getReference()->isValid()) { throw LuaException("Table reference is not valid!"); } this->pushValue(); table.pushValue(); bool ret = lua_setfenv(_luaState, -2) != 0; // Pop the function again lua_pop(_luaState, 1); return ret; }
void Lua::Load(const std::string& file) { if(m_isLoaded) Unload(); m_lua = luaL_newstate(); if(m_lua == NULL) { throw LuaException("Not enough resources to initialize the Lua engine."); return; } m_isLoaded = true; luaL_openlibs(m_lua); if (luaL_loadfile(m_lua, file.c_str()) || lua_pcall(m_lua, 0, 0, 0)) { std::string errorMessage = "The file '"; errorMessage += file; errorMessage += "' was not found or could not be loaded."; throw LuaException(errorMessage.c_str()); } }
void LuaInterface::loadScript(const std::string& fileName) { // resolve file full path std::string filePath = fileName; if(!boost::starts_with(fileName, "/")) filePath = getCurrentSourcePath() + "/" + filePath; try { std::string buffer = g_resources.loadFile(filePath); std::string source = "@" + filePath; loadBuffer(buffer, source); } catch(Exception& e) { throw LuaException(e.what()); } }
void Lua::checkLoadResult(int result, const char *name) { if (result == 0) { return; } std::stringstream buf; if (result == LUA_ERRFILE) { buf << "Failed to open " << name; } else if (result == LUA_ERRSYNTAX) { buf << "Syntax error in " << name; buf << std::endl << lua_tostring(L, -1); } else { buf << "Out of memory or other error while loading " << name; } throw LuaException(buf.str().c_str()); }
//------------------------------------------------------------------------------------------------- void LuaWorker::on_checkFile(const IFile *pFile) { if (m_pConsole==NULL || pFile==NULL) return; try { Q_ASSERT(pFile!=NULL); Locker lock(pFile); if (m_luaState==NULL) throw LuaException(QString("Can't execute Lua code fragment \"%1\": Lua state is not initialized").arg(pFile->getName())); // qDebug() << "syntaxCheck(" << pFile->getName() << ")"; const QVector<QString> &vLines = pFile->getLines(); QString sScript; for (int i=0; i<vLines.size(); ++i) { const QString &sLine = vLines[i]; sScript += sLine; } syntaxCheck(sScript, pFile->getName()); emit syntaxCheckSuccess(pFile); } catch(LuaException &exc) { exc.setFile(pFile); QString sMsg = QString("%1 in Line %2").arg(exc.getMessage()) .arg(exc.getLine()); emit syntaxCheckFail(pFile, sMsg, (int)exc.getLine()); } catch(Exception &exc) { emit syntaxCheckFail(pFile, exc.getMessage(), -1); } catch(std::exception &exc) { emit syntaxCheckFail(pFile, exc.what(), -1); } catch(...) { emit syntaxCheckFail(pFile, "Internal error: FrmConsole::executeCommand", -1); } }
/// @return non-zero on errors, and a description is available through getError() int Interpreter::doString(const std::string& str, const std::string& identifier) { errstr = ""; status = luaL_loadbuffer(luastate, str.c_str(), str.length(), identifier.c_str()); if (status != 0 && getTop() > 0) { if (lua_tostring(luastate, -1)) errstr = lua_tostring(luastate, -1); else { std::stringstream ss; ss << "doString returned " << status << " and top of stack is not string, stack:\n" << getStack(); throw LuaException(ss.str()); } lua_pop(luastate,1); return status; } // Run it return pCall(0,1,0,1); }
//------------------------------------------------------------------------------------------------- void LuaWorker::on_doFile(IFile *pFile) { if (m_pConsole==NULL || pFile==NULL) return; qDebug("on_doFile(%s); thread id: %d", pFile->getName().toStdString().c_str(), reinterpret_cast<int>(QThread::currentThreadId())); try { QVector<QString> vLines = pFile->getLines(); QString sScript; for (int i=0; i<vLines.size(); ++i) { sScript += vLines[i]; } if (m_luaState==NULL) throw LuaException(QString("Can't execute Lua code fragment \"%1\": Lua state is not initialized").arg(sScript)); doString(sScript, pFile->getName()); emit finished(); } catch(LuaException &exc) { exc.setFile(pFile); QString sMsg = QString("%1 in Line %2").arg(exc.getMessage()) .arg(exc.getLine()); emit error(sMsg); } catch(Exception &exc) { emit error(exc.getMessage()); } catch(std::exception &exc) { emit error(exc.what()); } catch(...) { emit error("Internal error: FrmConsole::executeCommand"); } }
/// @return non-zero on errors, and a description is available through getError() int Interpreter::doFile(const std::string& filename) { errstr = ""; // Load the data status = luaL_loadfile(luastate, filename.c_str()); if (status != 0 && getTop() > 0) { if (lua_tostring(luastate, -1)) errstr = lua_tostring(luastate, -1); else { std::stringstream ss; ss << "doFile returned " << status << " and top of stack is not string, stack:\n" << getStack(); throw LuaException(ss.str()); } lua_pop(luastate,1); return status; } // Run it return pCall(0,1,0,1); }