lua: added extended type() function and replaced in_instance() by get_class()

Dieser Commit ist enthalten in:
Reinder Feenstra 2021-11-20 00:27:00 +01:00
Ursprung efc2c2a602
Commit f7f289e1d6
6 geänderte Dateien mit 307 neuen und 73 gelöschten Zeilen

Datei anzeigen

@ -0,0 +1,39 @@
/**
* server/src/lua/checkarguments.hpp
*
* This file is part of the traintastic source code.
*
* Copyright (C) 2021 Reinder Feenstra
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef TRAINTASTIC_SERVER_LUA_CHECKARGUMENTS_HPP
#define TRAINTASTIC_SERVER_LUA_CHECKARGUMENTS_HPP
#include "error.hpp"
namespace Lua {
inline void checkArguments(lua_State* L, int count)
{
const int top = lua_gettop(L);
if(top != count)
errorExpectedNArgumentsGotN(L, count, top);
}
}
#endif

Datei anzeigen

@ -23,6 +23,7 @@
#include "class.hpp" #include "class.hpp"
#include "push.hpp" #include "push.hpp"
#include "object.hpp" #include "object.hpp"
#include "checkarguments.hpp"
#include "../board/board.hpp" #include "../board/board.hpp"
#include "../board/boardlist.hpp" #include "../board/boardlist.hpp"
@ -126,96 +127,148 @@ static bool isInstance(const ::ObjectPtr& object)
} }
template<class T> template<class T>
inline static void setField(lua_State* L, std::string_view key) inline static void registerValue(lua_State* L, std::string_view key)
{ {
static_assert(std::is_base_of_v<::Object, T>); static_assert(std::is_base_of_v<::Object, T>);
push(L, key);
// add to global class (used by Class::push)
lua_getglobal(L, metaTableName);
*reinterpret_cast<IsInstance*>(lua_newuserdata(L, sizeof(IsInstance))) = isInstance<T>; *reinterpret_cast<IsInstance*>(lua_newuserdata(L, sizeof(IsInstance))) = isInstance<T>;
luaL_newmetatable(L, metaTableName); if(luaL_newmetatable(L, metaTableName))
{
lua_pushcfunction(L, Class::__tostring);
lua_setfield(L, -2, "__tostring");
}
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
lua_rawsetp(L, -2, T::classId.data());
lua_pop(L, 1);
// add to sandbox class global:
Lua::push(L, key);
Class::push<T>(L);
lua_settable(L, -3); lua_settable(L, -3);
} }
void Class::registerValues(lua_State* L) void Class::registerValues(lua_State* L)
{ {
assert(lua_istable(L, -1)); assert(lua_istable(L, -1)); // sandboxes global class
setField<Board>(L, "BOARD"); lua_newtable(L); // global
setField<BoardList>(L, "BOARD_LIST"); lua_setglobal(L, metaTableName);
setField<StraightRailTile>(L, "STRAIGHT_RAIL_TILE"); registerValue<Board>(L, "BOARD");
setField<TunnelRailTile>(L, "TUNNEL_RAIL_TILE"); registerValue<BoardList>(L, "BOARD_LIST");
setField<BufferStopRailTile>(L, "BUFFER_STOP_RAIL_TILE");
setField<Curve45RailTile>(L, "CURVE_45_RAIL_TILE");
setField<Curve90RailTile>(L, "CURVE_90_RAIL_TILE");
setField<Cross45RailTile>(L, "CROSS_45_RAIL_TILE");
setField<Cross90RailTile>(L, "CROSS_90_RAIL_TILE");
setField<Bridge45RightRailTile>(L, "BRIDGE_45_RIGHT_RAIL_TILE");
setField<Bridge45LeftRailTile>(L, "BRIDGE_45_LEFT_RAIL_TILE");
setField<Bridge90RailTile>(L, "BRIDGE_90_RAIL_TILE");
setField<TurnoutSingleSlipRailTile>(L, "TURNOUT_SINGLE_SLIP_RAIL_TILE");
setField<TurnoutLeft90RailTile>(L, "TURNOUT_LEFT_90_RAIL_TILE");
setField<TurnoutRight45RailTile>(L, "TURNOUT_RIGHT_45_RAIL_TILE");
setField<TurnoutLeft45RailTile>(L, "TURNOUT_LEFT_45_RAIL_TILE");
setField<TurnoutRight90RailTile>(L, "TURNOUT_RIGHT_90_RAIL_TILE");
setField<TurnoutDoubleSlipRailTile>(L, "TURNOUT_DOUBLE_SLIP_RAIL_TILE");
setField<TurnoutWyeRailTile>(L, "TURNOUT_WYE_RAIL_TILE");
setField<TurnoutLeftCurvedRailTile>(L, "TURNOUT__RAIL_TILE");
setField<Turnout3WayRailTile>(L, "TURNOUT_3WAY_RAIL_TILE");
setField<TurnoutRightCurvedRailTile>(L, "TURNOUT_RIGHT_CURVED_RAIL_TILE");
setField<Signal2AspectRailTile>(L, "SIGNAL_2_ASPECT_RAIL_TILE");
setField<Signal3AspectRailTile>(L, "SIGNAL_3_ASPECT_RAIL_TILE");
setField<SensorRailTile>(L, "SENSOR_RAIL_TILE");
setField<BlockRailTile>(L, "BLOCK_RAIL_TILE");
setField<Clock>(L, "CLOCK"); registerValue<StraightRailTile>(L, "STRAIGHT_RAIL_TILE");
registerValue<TunnelRailTile>(L, "TUNNEL_RAIL_TILE");
registerValue<BufferStopRailTile>(L, "BUFFER_STOP_RAIL_TILE");
registerValue<Curve45RailTile>(L, "CURVE_45_RAIL_TILE");
registerValue<Curve90RailTile>(L, "CURVE_90_RAIL_TILE");
registerValue<Cross45RailTile>(L, "CROSS_45_RAIL_TILE");
registerValue<Cross90RailTile>(L, "CROSS_90_RAIL_TILE");
registerValue<Bridge45RightRailTile>(L, "BRIDGE_45_RIGHT_RAIL_TILE");
registerValue<Bridge45LeftRailTile>(L, "BRIDGE_45_LEFT_RAIL_TILE");
registerValue<Bridge90RailTile>(L, "BRIDGE_90_RAIL_TILE");
registerValue<TurnoutSingleSlipRailTile>(L, "TURNOUT_SINGLE_SLIP_RAIL_TILE");
registerValue<TurnoutLeft90RailTile>(L, "TURNOUT_LEFT_90_RAIL_TILE");
registerValue<TurnoutRight45RailTile>(L, "TURNOUT_RIGHT_45_RAIL_TILE");
registerValue<TurnoutLeft45RailTile>(L, "TURNOUT_LEFT_45_RAIL_TILE");
registerValue<TurnoutRight90RailTile>(L, "TURNOUT_RIGHT_90_RAIL_TILE");
registerValue<TurnoutDoubleSlipRailTile>(L, "TURNOUT_DOUBLE_SLIP_RAIL_TILE");
registerValue<TurnoutWyeRailTile>(L, "TURNOUT_WYE_RAIL_TILE");
registerValue<TurnoutLeftCurvedRailTile>(L, "TURNOUT__RAIL_TILE");
registerValue<Turnout3WayRailTile>(L, "TURNOUT_3WAY_RAIL_TILE");
registerValue<TurnoutRightCurvedRailTile>(L, "TURNOUT_RIGHT_CURVED_RAIL_TILE");
registerValue<Signal2AspectRailTile>(L, "SIGNAL_2_ASPECT_RAIL_TILE");
registerValue<Signal3AspectRailTile>(L, "SIGNAL_3_ASPECT_RAIL_TILE");
registerValue<SensorRailTile>(L, "SENSOR_RAIL_TILE");
registerValue<BlockRailTile>(L, "BLOCK_RAIL_TILE");
setField<WLANmaus>(L, "WLANMAUS_CONTROLLER"); registerValue<Clock>(L, "CLOCK");
setField<ControllerList>(L, "CONTROLLER_LIST");
registerValue<WLANmaus>(L, "WLANMAUS_CONTROLLER");
registerValue<ControllerList>(L, "CONTROLLER_LIST");
#ifdef USB_XPRESSNET #ifdef USB_XPRESSNET
setField<USBXpressNetController>(L, "USB_XPRESSNET_CONTROLLER"); registerValue<USBXpressNetController>(L, "USB_XPRESSNET_CONTROLLER");
#endif #endif
setField<RocoZ21>(L, "Z21_COMMAND_STATION"); registerValue<RocoZ21>(L, "Z21_COMMAND_STATION");
setField<VirtualCommandStation>(L, "VIRTUAL_COMMAND_STATION"); registerValue<VirtualCommandStation>(L, "VIRTUAL_COMMAND_STATION");
setField<LocoNetTCPBinary>(L, "LOCONET_TCP_BINARY_COMMAND_STATION"); registerValue<LocoNetTCPBinary>(L, "LOCONET_TCP_BINARY_COMMAND_STATION");
#ifdef USB_XPRESSNET #ifdef USB_XPRESSNET
setField<USBXpressNetInterface>(L, "USB_XPRESSNET_INTERFACE"); registerValue<USBXpressNetInterface>(L, "USB_XPRESSNET_INTERFACE");
#endif #endif
setField<XpressNetSerial>(L, "XPRESSNET_SERIAL_COMMAND_STATION"); registerValue<XpressNetSerial>(L, "XPRESSNET_SERIAL_COMMAND_STATION");
setField<DCCPlusPlusSerial>(L, "DCCPLUSPLUS_SERIAL_COMMAND_STATION"); registerValue<DCCPlusPlusSerial>(L, "DCCPLUSPLUS_SERIAL_COMMAND_STATION");
setField<CommandStationList>(L, "COMMAND_STATION_LIST"); registerValue<CommandStationList>(L, "COMMAND_STATION_LIST");
setField<LocoNetSerial>(L, "LOCONET_SERIAL_COMMAND_STATION"); registerValue<LocoNetSerial>(L, "LOCONET_SERIAL_COMMAND_STATION");
setField<DecoderFunction>(L, "DECODER_FUNCTION"); registerValue<DecoderFunction>(L, "DECODER_FUNCTION");
setField<DecoderList>(L, "DECODER_LIST"); registerValue<DecoderList>(L, "DECODER_LIST");
setField<Decoder>(L, "DECODER"); registerValue<Decoder>(L, "DECODER");
setField<DecoderFunctions>(L, "DECODER_FUNCTIONS"); registerValue<DecoderFunctions>(L, "DECODER_FUNCTIONS");
setField<LocoNetInput>(L, "LOCONET_INPUT"); registerValue<LocoNetInput>(L, "LOCONET_INPUT");
setField<XpressNetInput>(L, "XPRESSNET_INPUT"); registerValue<XpressNetInput>(L, "XPRESSNET_INPUT");
setField<InputList>(L, "INPUT_LIST"); registerValue<InputList>(L, "INPUT_LIST");
setField<OutputList>(L, "OUTPUT_LIST"); registerValue<OutputList>(L, "OUTPUT_LIST");
setField<LocoNetOutput>(L, "LOCONET_OUTPUT"); registerValue<LocoNetOutput>(L, "LOCONET_OUTPUT");
setField<RailVehicleList>(L, "RAIL_VEHICLE_LIST"); registerValue<RailVehicleList>(L, "RAIL_VEHICLE_LIST");
setField<Locomotive>(L, "LOCOMOTIVE"); registerValue<Locomotive>(L, "LOCOMOTIVE");
setField<FreightCar>(L, "FREIGHT_CAR"); registerValue<FreightCar>(L, "FREIGHT_CAR");
setField<Train>(L, "TRAIN"); registerValue<Train>(L, "TRAIN");
setField<TrainList>(L, "TRAIN_LIST"); registerValue<TrainList>(L, "TRAIN_LIST");
setField<World>(L, "WORLD"); registerValue<World>(L, "WORLD");
} }
int Class::isInstance(lua_State* L) void Class::push(lua_State* L, std::string_view classId)
{ {
if(lua_gettop(L) != 2) lua_getglobal(L, metaTableName);
errorExpectedNArgumentsGotN(L, 2, lua_gettop(L)); assert(lua_istable(L, -1));
lua_rawgetp(L, -1, classId.data());
assert(lua_isuserdata(L, -1));
lua_insert(L, lua_gettop(L) - 1);
lua_pop(L, 1);
assert(lua_isuserdata(L, -1));
}
push(L, (*reinterpret_cast<IsInstance*>(luaL_checkudata(L, 2, metaTableName)))(Object::test(L, 1))); void Class::push(lua_State* L, const ObjectPtr& object)
{
push(L, object->getClassId());
}
int Class::__tostring(lua_State* L)
{
Sandbox::getGlobal(L, metaTableName);
// get the real table, the global is wrapped for write protection:
lua_getmetatable(L, -1);
lua_getfield(L, -1, "__index");
assert(lua_istable(L, -1));
// loop over table to find value and the return key
const int idx = lua_gettop(L);
lua_pushnil(L);
while(lua_next(L, idx))
{
const bool eq = lua_compare(L, 1, -1, LUA_OPEQ);
lua_pop(L, 1); // pop value
if(eq)
return 1;
}
lua_pushlstring(L, NULL, 0);
return 1;
}
int Class::getClass(lua_State* L)
{
checkArguments(L, 1);
push(L, Object::check(L, 1));
return 1; return 1;
} }

Datei anzeigen

@ -32,7 +32,19 @@ struct Class
{ {
static void registerValues(lua_State* L); static void registerValues(lua_State* L);
static int isInstance(lua_State* L); static void push(lua_State* L, std::string_view classId);
static void push(lua_State* L, const ObjectPtr& object);
template<class T>
static void push(lua_State* L)
{
static_assert(std::is_base_of_v<::Object, T>);
push(L, T::classId);
}
static int __tostring(lua_State* L);
static int getClass(lua_State* L);
}; };
} }

Datei anzeigen

@ -27,6 +27,7 @@
#include "log.hpp" #include "log.hpp"
#include "class.hpp" #include "class.hpp"
#include "to.hpp" #include "to.hpp"
#include "type.hpp"
#include <version.hpp> #include <version.hpp>
#include <traintastic/utils/str.hpp> #include <traintastic/utils/str.hpp>
#include <traintastic/codename.hpp> #include <traintastic/codename.hpp>
@ -72,7 +73,17 @@ constexpr std::array<std::string_view, 23> readOnlyGlobals = {{
"set", "set",
}}; }};
static void addBaseLib(lua_State* L, std::initializer_list<const char*> names) static void addExtensions(lua_State* L, std::initializer_list<std::pair<const char*, lua_CFunction>> extensions)
{
assert(lua_istable(L, -1));
for(auto [name, func] : extensions)
{
lua_pushcfunction(L, func);
lua_setfield(L, -2, name);
}
}
static void addBaseLib(lua_State* L, std::initializer_list<const char*> names, std::initializer_list<std::pair<const char*, lua_CFunction>> extensions = {})
{ {
// load Lua baselib: // load Lua baselib:
lua_pushcfunction(L, luaopen_base); lua_pushcfunction(L, luaopen_base);
@ -85,11 +96,13 @@ static void addBaseLib(lua_State* L, std::initializer_list<const char*> names)
assert(!lua_isnil(L, -1)); assert(!lua_isnil(L, -1));
lua_setfield(L, -2, name); lua_setfield(L, -2, name);
} }
addExtensions(L, extensions);
} }
static void addLib(lua_State* L, const char* libraryName, lua_CFunction openFunction, std::initializer_list<const char*> names) static void addLib(lua_State* L, const char* libraryName, lua_CFunction openFunction, std::initializer_list<const char*> names, std::initializer_list<std::pair<const char*, lua_CFunction>> extensions = {})
{ {
lua_createtable(L, 0, names.size()); lua_createtable(L, 0, names.size() + extensions.size());
luaL_requiref(L, libraryName, openFunction, 1); luaL_requiref(L, libraryName, openFunction, 1);
@ -102,6 +115,8 @@ static void addLib(lua_State* L, const char* libraryName, lua_CFunction openFunc
lua_pop(L, 1); // pop lib lua_pop(L, 1); // pop lib
addExtensions(L, extensions);
Lua::ReadOnlyTable::wrap(L, -1); Lua::ReadOnlyTable::wrap(L, -1);
lua_setfield(L, -2, libraryName); lua_setfield(L, -2, libraryName);
} }
@ -166,9 +181,14 @@ SandboxPtr Sandbox::create(Script& script)
// setup globals: // setup globals:
lua_newtable(L); lua_newtable(L);
// add Lua lib functions: // add standard Lua lib functions and extensions/replacements:
addBaseLib(L, { addBaseLib(L,
"assert", "type", "pairs", "ipairs", "next", "tonumber", "tostring", {
"assert", "pairs", "ipairs", "next", "tonumber", "tostring",
},
{
{"type", type},
{"get_class", Class::getClass},
}); });
addLib(L, LUA_MATHLIBNAME, luaopen_math, { addLib(L, LUA_MATHLIBNAME, luaopen_math, {
"abs", "acos", "asin", "atan", "ceil", "cos", "deg", "exp", "abs", "acos", "asin", "atan", "ceil", "cos", "deg", "exp",
@ -211,10 +231,6 @@ SandboxPtr Sandbox::create(Script& script)
Log::push(L); Log::push(L);
lua_setfield(L, -2, "log"); lua_setfield(L, -2, "log");
// add is_instance function:
lua_pushcfunction(L, Class::isInstance);
lua_setfield(L, -2, "is_instance");
// add class types: // add class types:
lua_newtable(L); lua_newtable(L);
Class::registerValues(L); Class::registerValues(L);
@ -252,7 +268,7 @@ Sandbox::StateData& Sandbox::getStateData(lua_State* L)
int Sandbox::getGlobal(lua_State* L, const char* name) int Sandbox::getGlobal(lua_State* L, const char* name)
{ {
lua_getglobal(L, LUA_SANDBOX); // get the sandbox lua_getglobal(L, LUA_SANDBOX_GLOBALS); // get the sandbox
lua_pushstring(L, name); lua_pushstring(L, name);
const int type = lua_gettable(L, -2); // get item const int type = lua_gettable(L, -2); // get item
lua_insert(L, lua_gettop(L) - 1); // swap item and sandbox on the stack lua_insert(L, lua_gettop(L) - 1); // swap item and sandbox on the stack

80
server/src/lua/type.cpp Normale Datei
Datei anzeigen

@ -0,0 +1,80 @@
/**
* server/src/lua/type.cpp
*
* This file is part of the traintastic source code.
*
* Copyright (C) 2021 Reinder Feenstra
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "type.hpp"
#include "object.hpp"
#include "class.hpp"
#include "sandbox.hpp"
namespace Lua {
int type(lua_State* L)
{
const int tp = lua_type(L, 1);
if(tp == LUA_TUSERDATA)
{
if(auto object = Object::test(L, 1))
{
lua_pushstring(L, "object");
Class::push(L, object);
return 2;
}
if(lua_getmetatable(L, 1))
{
lua_getfield(L, -1, "__name");
const char* name = lua_tostring(L, -1);
// check for enum:
Sandbox::getGlobal(L, "enum");
lua_getfield(L, -1, name);
if(lua_istable(L, -1))
{
lua_pop(L, 2);
lua_pushstring(L, "enum");
lua_replace(L, -3);
return 2;
}
else
lua_pop(L, 2);
// check for set:
Sandbox::getGlobal(L, "set");
lua_getfield(L, -1, name);
if(lua_istable(L, -1))
{
lua_pop(L, 2);
lua_pushstring(L, "set");
lua_replace(L, -3);
return 2;
}
else
lua_pop(L, 2);
}
}
lua_pushstring(L, lua_typename(L, tp));
return 1;
}
}

34
server/src/lua/type.hpp Normale Datei
Datei anzeigen

@ -0,0 +1,34 @@
/**
* server/src/lua/type.hpp
*
* This file is part of the traintastic source code.
*
* Copyright (C) 2021 Reinder Feenstra
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef TRAINTASTIC_SERVER_LUA_TYPE_HPP
#define TRAINTASTIC_SERVER_LUA_TYPE_HPP
#include <lua.hpp>
namespace Lua {
int type(lua_State* L);
}
#endif