[Lua] makeStrictReadOnly for enums

pull/3227/head
Petr Mikheev 3 years ago
parent be100749f8
commit 7ccbf95503

@ -17,7 +17,7 @@ namespace MWLua
MWRender::RenderingManager* renderingManager = MWBase::Environment::get().getWorld()->getRenderingManager(); MWRender::RenderingManager* renderingManager = MWBase::Environment::get().getWorld()->getRenderingManager();
sol::table api(context.mLua->sol(), sol::create); sol::table api(context.mLua->sol(), sol::create);
api["MODE"] = LuaUtil::makeReadOnly(context.mLua->sol().create_table_with( api["MODE"] = LuaUtil::makeStrictReadOnly(context.mLua->sol().create_table_with(
"Static", CameraMode::Static, "Static", CameraMode::Static,
"FirstPerson", CameraMode::FirstPerson, "FirstPerson", CameraMode::FirstPerson,
"ThirdPerson", CameraMode::ThirdPerson, "ThirdPerson", CameraMode::ThirdPerson,

@ -87,7 +87,7 @@ namespace MWLua
return SDL_GetKeyName(SDL_GetKeyFromScancode(code)); return SDL_GetKeyName(SDL_GetKeyFromScancode(code));
}; };
api["ACTION"] = LuaUtil::makeReadOnly(context.mLua->tableFromPairs<std::string_view, MWInput::Actions>({ api["ACTION"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, MWInput::Actions>({
{"GameMenu", MWInput::A_GameMenu}, {"GameMenu", MWInput::A_GameMenu},
{"Screenshot", MWInput::A_Screenshot}, {"Screenshot", MWInput::A_Screenshot},
{"Inventory", MWInput::A_Inventory}, {"Inventory", MWInput::A_Inventory},
@ -141,7 +141,7 @@ namespace MWLua
{"ZoomOut", MWInput::A_ZoomOut} {"ZoomOut", MWInput::A_ZoomOut}
})); }));
api["CONTROL_SWITCH"] = LuaUtil::makeReadOnly(context.mLua->tableFromPairs<std::string_view, std::string_view>({ api["CONTROL_SWITCH"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, std::string_view>({
{"Controls", "playercontrols"}, {"Controls", "playercontrols"},
{"Fighting", "playerfighting"}, {"Fighting", "playerfighting"},
{"Jumping", "playerjumping"}, {"Jumping", "playerjumping"},
@ -151,7 +151,7 @@ namespace MWLua
{"VanityMode", "vanitymode"} {"VanityMode", "vanitymode"}
})); }));
api["CONTROLLER_BUTTON"] = LuaUtil::makeReadOnly(context.mLua->tableFromPairs<std::string_view, SDL_GameControllerButton>({ api["CONTROLLER_BUTTON"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, SDL_GameControllerButton>({
{"A", SDL_CONTROLLER_BUTTON_A}, {"A", SDL_CONTROLLER_BUTTON_A},
{"B", SDL_CONTROLLER_BUTTON_B}, {"B", SDL_CONTROLLER_BUTTON_B},
{"X", SDL_CONTROLLER_BUTTON_X}, {"X", SDL_CONTROLLER_BUTTON_X},
@ -169,7 +169,7 @@ namespace MWLua
{"DPadRight", SDL_CONTROLLER_BUTTON_DPAD_RIGHT} {"DPadRight", SDL_CONTROLLER_BUTTON_DPAD_RIGHT}
})); }));
api["CONTROLLER_AXIS"] = LuaUtil::makeReadOnly(context.mLua->tableFromPairs<std::string_view, int>({ api["CONTROLLER_AXIS"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, int>({
{"LeftX", SDL_CONTROLLER_AXIS_LEFTX}, {"LeftX", SDL_CONTROLLER_AXIS_LEFTX},
{"LeftY", SDL_CONTROLLER_AXIS_LEFTY}, {"LeftY", SDL_CONTROLLER_AXIS_LEFTY},
{"RightX", SDL_CONTROLLER_AXIS_RIGHTX}, {"RightX", SDL_CONTROLLER_AXIS_RIGHTX},
@ -183,7 +183,7 @@ namespace MWLua
{"MoveLeftRight", SDL_CONTROLLER_AXIS_MAX + static_cast<int>(MWInput::A_MoveLeftRight)} {"MoveLeftRight", SDL_CONTROLLER_AXIS_MAX + static_cast<int>(MWInput::A_MoveLeftRight)}
})); }));
api["KEY"] = LuaUtil::makeReadOnly(context.mLua->tableFromPairs<std::string_view, SDL_Scancode>({ api["KEY"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, SDL_Scancode>({
{"_0", SDL_SCANCODE_0}, {"_0", SDL_SCANCODE_0},
{"_1", SDL_SCANCODE_1}, {"_1", SDL_SCANCODE_1},
{"_2", SDL_SCANCODE_2}, {"_2", SDL_SCANCODE_2},

@ -47,7 +47,7 @@ namespace MWLua
return LObject(getId(r.mHitObject), worldView->getObjectRegistry()); return LObject(getId(r.mHitObject), worldView->getObjectRegistry());
}); });
api["COLLISION_TYPE"] = LuaUtil::makeReadOnly(context.mLua->tableFromPairs<std::string_view, MWPhysics::CollisionType>({ api["COLLISION_TYPE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, MWPhysics::CollisionType>({
{"World", MWPhysics::CollisionType_World}, {"World", MWPhysics::CollisionType_World},
{"Door", MWPhysics::CollisionType_Door}, {"Door", MWPhysics::CollisionType_Door},
{"Actor", MWPhysics::CollisionType_Actor}, {"Actor", MWPhysics::CollisionType_Actor},

@ -113,12 +113,12 @@ namespace MWLua
void addActorBindings(sol::table actor, const Context& context) void addActorBindings(sol::table actor, const Context& context)
{ {
actor["STANCE"] = LuaUtil::makeReadOnly(context.mLua->tableFromPairs<std::string_view, int>({ actor["STANCE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, int>({
{"Nothing", MWMechanics::DrawState_Nothing}, {"Nothing", MWMechanics::DrawState_Nothing},
{"Weapon", MWMechanics::DrawState_Weapon}, {"Weapon", MWMechanics::DrawState_Weapon},
{"Spell", MWMechanics::DrawState_Spell}, {"Spell", MWMechanics::DrawState_Spell},
})); }));
actor["EQUIPMENT_SLOT"] = LuaUtil::makeReadOnly(context.mLua->tableFromPairs<std::string_view, int>({ actor["EQUIPMENT_SLOT"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, int>({
{"Helmet", MWWorld::InventoryStore::Slot_Helmet}, {"Helmet", MWWorld::InventoryStore::Slot_Helmet},
{"Cuirass", MWWorld::InventoryStore::Slot_Cuirass}, {"Cuirass", MWWorld::InventoryStore::Slot_Cuirass},
{"Greaves", MWWorld::InventoryStore::Slot_Greaves}, {"Greaves", MWWorld::InventoryStore::Slot_Greaves},

@ -16,7 +16,7 @@ namespace MWLua
{ {
void addWeaponBindings(sol::table weapon, const Context& context) void addWeaponBindings(sol::table weapon, const Context& context)
{ {
weapon["TYPE"] = LuaUtil::makeReadOnly(context.mLua->tableFromPairs<std::string_view, int>({ weapon["TYPE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, int>({
{"ShortBladeOneHand", ESM::Weapon::ShortBladeOneHand}, {"ShortBladeOneHand", ESM::Weapon::ShortBladeOneHand},
{"LongBladeOneHand", ESM::Weapon::LongBladeOneHand}, {"LongBladeOneHand", ESM::Weapon::LongBladeOneHand},
{"LongBladeTwoHand", ESM::Weapon::LongBladeTwoHand}, {"LongBladeTwoHand", ESM::Weapon::LongBladeTwoHand},

@ -183,7 +183,7 @@ namespace MWLua
{ {
luaManager->addUIMessage(message); luaManager->addUIMessage(message);
}; };
api["CONSOLE_COLOR"] = LuaUtil::makeReadOnly(context.mLua->tableFromPairs<std::string, Misc::Color>({ api["CONSOLE_COLOR"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string, Misc::Color>({
{"Default", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Default.substr(1))}, {"Default", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Default.substr(1))},
{"Error", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Error.substr(1))}, {"Error", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Error.substr(1))},
{"Success", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Success.substr(1))}, {"Success", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Success.substr(1))},
@ -298,9 +298,9 @@ namespace MWLua
sol::table typeTable = context.mLua->newTable(); sol::table typeTable = context.mLua->newTable();
for (const auto& it : LuaUi::widgetTypeToName()) for (const auto& it : LuaUi::widgetTypeToName())
typeTable.set(it.second, it.first); typeTable.set(it.second, it.first);
api["TYPE"] = LuaUtil::makeReadOnly(typeTable); api["TYPE"] = LuaUtil::makeStrictReadOnly(typeTable);
api["ALIGNMENT"] = LuaUtil::makeReadOnly(context.mLua->tableFromPairs<std::string_view, LuaUi::Alignment>({ api["ALIGNMENT"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, LuaUi::Alignment>({
{ "Start", LuaUi::Alignment::Start }, { "Start", LuaUi::Alignment::Start },
{ "Center", LuaUi::Alignment::Center }, { "Center", LuaUi::Alignment::Center },
{ "End", LuaUi::Alignment::End } { "End", LuaUi::Alignment::End }

@ -84,12 +84,22 @@ namespace LuaUtil
end end
printGen = function(name) return function(...) return printToLog(name, ...) end end printGen = function(name) return function(...) return printToLog(name, ...) end end
function createStrictIndexFn(tbl)
return function(_, key)
local res = tbl[key]
if res ~= nil then
return res
else
error('Key not found: '..tostring(key), 2)
end
end
end
function pairsForReadOnly(v) function pairsForReadOnly(v)
local nextFn, t, firstKey = pairs(getmetatable(v).__index) local nextFn, t, firstKey = pairs(getmetatable(v).t)
return function(_, k) return nextFn(t, k) end, v, firstKey return function(_, k) return nextFn(t, k) end, v, firstKey
end end
function ipairsForReadOnly(v) function ipairsForReadOnly(v)
local nextFn, t, firstKey = ipairs(getmetatable(v).__index) local nextFn, t, firstKey = ipairs(getmetatable(v).t)
return function(_, k) return nextFn(t, k) end, v, firstKey return function(_, k) return nextFn(t, k) end, v, firstKey
end end
local function nextForArray(array, index) local function nextForArray(array, index)
@ -136,7 +146,7 @@ namespace LuaUtil
mSandboxEnv = sol::nil; mSandboxEnv = sol::nil;
} }
sol::table makeReadOnly(sol::table table) sol::table makeReadOnly(const sol::table& table, bool strictIndex)
{ {
if (table == sol::nil) if (table == sol::nil)
return table; return table;
@ -146,7 +156,11 @@ namespace LuaUtil
lua_State* luaState = table.lua_state(); lua_State* luaState = table.lua_state();
sol::state_view lua(luaState); sol::state_view lua(luaState);
sol::table meta(lua, sol::create); sol::table meta(lua, sol::create);
meta["__index"] = table; meta["t"] = table;
if (strictIndex)
meta["__index"] = lua["createStrictIndexFn"](table);
else
meta["__index"] = table;
meta["__pairs"] = lua["pairsForReadOnly"]; meta["__pairs"] = lua["pairsForReadOnly"];
meta["__ipairs"] = lua["ipairsForReadOnly"]; meta["__ipairs"] = lua["ipairsForReadOnly"];
@ -158,7 +172,7 @@ namespace LuaUtil
sol::table getMutableFromReadOnly(const sol::userdata& ro) sol::table getMutableFromReadOnly(const sol::userdata& ro)
{ {
return ro[sol::metatable_key].get<sol::table>()["__index"]; return ro[sol::metatable_key].get<sol::table>()["t"];
} }
void LuaState::addCommonPackage(std::string packageName, sol::object package) void LuaState::addCommonPackage(std::string packageName, sol::object package)

@ -139,7 +139,9 @@ namespace LuaUtil
// Makes a table read only (when accessed from Lua) by wrapping it with an empty userdata. // Makes a table read only (when accessed from Lua) by wrapping it with an empty userdata.
// Needed to forbid any changes in common resources that can be accessed from different sandboxes. // Needed to forbid any changes in common resources that can be accessed from different sandboxes.
sol::table makeReadOnly(sol::table); // `strictIndex = true` replaces default `__index` with a strict version that throws an error if key is not found.
sol::table makeReadOnly(const sol::table&, bool strictIndex = false);
inline sol::table makeStrictReadOnly(const sol::table& tbl) { return makeReadOnly(tbl, true); }
sol::table getMutableFromReadOnly(const sol::userdata&); sol::table getMutableFromReadOnly(const sol::userdata&);
} }

@ -214,7 +214,8 @@ namespace LuaUtil
util["clamp"] = [](float value, float from, float to) { return std::clamp(value, from, to); }; util["clamp"] = [](float value, float from, float to) { return std::clamp(value, from, to); };
// NOTE: `util["clamp"] = std::clamp<float>` causes error 'AddressSanitizer: stack-use-after-scope' // NOTE: `util["clamp"] = std::clamp<float>` causes error 'AddressSanitizer: stack-use-after-scope'
util["normalizeAngle"] = &Misc::normalizeAngle; util["normalizeAngle"] = &Misc::normalizeAngle;
util["makeReadOnly"] = &makeReadOnly; util["makeReadOnly"] = [](const sol::table& tbl) { return makeReadOnly(tbl, /*strictIndex=*/false); };
util["makeStrictReadOnly"] = [](const sol::table& tbl) { return makeReadOnly(tbl, /*strictIndex=*/true); };
if (lua["bit32"] != sol::nil) if (lua["bit32"] != sol::nil)
{ {

@ -25,6 +25,12 @@
-- @param #table table Any table. -- @param #table table Any table.
-- @return #table The same table wrapped with read only userdata. -- @return #table The same table wrapped with read only userdata.
---
-- Makes a table read only and overrides `__index` with the strict version that throws an error if the key is not found.
-- @function [parent=#util] makeStrictReadOnly
-- @param #table table Any table.
-- @return #table The same table wrapped with read only userdata.
--- ---
-- Parses Lua code from string and returns as a function. -- Parses Lua code from string and returns as a function.
-- @function [parent=#util] loadCode -- @function [parent=#util] loadCode

Loading…
Cancel
Save