/* * LuaStack.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ #include "StdInc.h" #include "LuaStack.h" #include "../../lib/JsonNode.h" #include "../../lib/int3.h" VCMI_LIB_NAMESPACE_BEGIN namespace scripting { LuaStack::LuaStack(lua_State * L_) : L(L_) { initialTop = lua_gettop(L); } void LuaStack::balance() { lua_settop(L, initialTop); } void LuaStack::clear() { lua_settop(L, 0); } void LuaStack::pushByIndex(lua_Integer index) { lua_pushvalue(L, index); } void LuaStack::pushNil() { lua_pushnil(L); } void LuaStack::pushInteger(lua_Integer value) { lua_pushinteger(L, value); } void LuaStack::push(bool value) { lua_pushboolean(L, value); } void LuaStack::push(const char * value) { lua_pushstring(L, value); } void LuaStack::push(const std::string & value) { lua_pushlstring(L, value.c_str(), value.size()); } void LuaStack::push(const int3 & value) { push(value.x); push(value.y); push(value.z); } void LuaStack::push(const JsonNode & value) { switch(value.getType()) { case JsonNode::JsonType::DATA_BOOL: { push(value.Bool()); } break; case JsonNode::JsonType::DATA_FLOAT: { lua_pushnumber(L, value.Float()); } break; case JsonNode::JsonType::DATA_INTEGER: { pushInteger(value.Integer()); } break; case JsonNode::JsonType::DATA_STRUCT: { lua_newtable(L); for(auto & keyValue : value.Struct()) { push(keyValue.first); push(keyValue.second); lua_rawset(L, -3); } } break; case JsonNode::JsonType::DATA_STRING: push(value.String()); break; case JsonNode::JsonType::DATA_VECTOR: { lua_newtable(L); for(int idx = 0; idx < value.Vector().size(); idx++) { pushInteger(idx + 1); push(value.Vector()[idx]); lua_rawset(L, -3); } } break; default: pushNil(); break; } } bool LuaStack::tryGet(int position, bool & value) { if(!lua_isboolean(L, position)) return false; value = (lua_toboolean(L, position) != 0); return true; } bool LuaStack::tryGet(int position, double & value) { if(!lua_isnumber(L, position)) return false; value = lua_tonumber(L, position); return true; } bool LuaStack::tryGetInteger(int position, lua_Integer & value) { if(!lua_isnumber(L, position)) return false; value = lua_tointeger(L, position); return true; } bool LuaStack::tryGet(int position, std::string & value) { if(!lua_isstring(L, position)) return false; size_t len = 0; auto raw = lua_tolstring(L, position, &len); value = std::string(raw, len); return true; } bool LuaStack::tryGet(int position, int3 & value) { return tryGet(position, value.x) && tryGet(position+1, value.y) && tryGet(position+2, value.z); } bool LuaStack::tryGet(int position, JsonNode & value) { auto type = lua_type(L, position); switch(type) { case LUA_TNIL: value.clear(); return true; case LUA_TNUMBER: return tryGet(position, value.Float()); case LUA_TBOOLEAN: value.Bool() = (lua_toboolean(L, position) != 0); return true; case LUA_TSTRING: return tryGet(position, value.String()); case LUA_TTABLE: { JsonNode asVector(JsonNode::JsonType::DATA_VECTOR); JsonNode asStruct(JsonNode::JsonType::DATA_STRUCT); lua_pushnil(L); /* first key */ while(lua_next(L, position) != 0) { /* 'key' (at index -2) and 'value' (at index -1) */ JsonNode fieldValue; if(!tryGet(lua_gettop(L), fieldValue)) { lua_pop(L, 2); value.clear(); return false; } lua_pop(L, 1); //pop value if(lua_type(L, -1) == LUA_TNUMBER) { auto key = lua_tointeger(L, -1); if(key > 0) { if(asVector.Vector().size() < key) asVector.Vector().resize(key); --key; asVector.Vector().at(key) = fieldValue; } } else if(lua_isstring(L, -1)) { std::string key; tryGet(-1, key); asStruct[key] = fieldValue; } } if(!asVector.Vector().empty()) { std::swap(value, asVector); } else { std::swap(value, asStruct); } } return true; default: value.clear(); return false; } } int LuaStack::retNil() { clear(); pushNil(); return 1; } int LuaStack::retVoid() { clear(); return 0; } } VCMI_LIB_NAMESPACE_END