[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();
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,
"FirstPerson", CameraMode::FirstPerson,
"ThirdPerson", CameraMode::ThirdPerson,

@ -87,7 +87,7 @@ namespace MWLua
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},
{"Screenshot", MWInput::A_Screenshot},
{"Inventory", MWInput::A_Inventory},
@ -141,7 +141,7 @@ namespace MWLua
{"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"},
{"Fighting", "playerfighting"},
{"Jumping", "playerjumping"},
@ -151,7 +151,7 @@ namespace MWLua
{"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},
{"B", SDL_CONTROLLER_BUTTON_B},
{"X", SDL_CONTROLLER_BUTTON_X},
@ -169,7 +169,7 @@ namespace MWLua
{"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},
{"LeftY", SDL_CONTROLLER_AXIS_LEFTY},
{"RightX", SDL_CONTROLLER_AXIS_RIGHTX},
@ -183,7 +183,7 @@ namespace MWLua
{"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},
{"_1", SDL_SCANCODE_1},
{"_2", SDL_SCANCODE_2},

@ -47,7 +47,7 @@ namespace MWLua
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},
{"Door", MWPhysics::CollisionType_Door},
{"Actor", MWPhysics::CollisionType_Actor},

@ -113,12 +113,12 @@ namespace MWLua
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},
{"Weapon", MWMechanics::DrawState_Weapon},
{"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},
{"Cuirass", MWWorld::InventoryStore::Slot_Cuirass},
{"Greaves", MWWorld::InventoryStore::Slot_Greaves},

@ -16,7 +16,7 @@ namespace MWLua
{
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},
{"LongBladeOneHand", ESM::Weapon::LongBladeOneHand},
{"LongBladeTwoHand", ESM::Weapon::LongBladeTwoHand},

@ -183,7 +183,7 @@ namespace MWLua
{
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))},
{"Error", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Error.substr(1))},
{"Success", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Success.substr(1))},
@ -298,9 +298,9 @@ namespace MWLua
sol::table typeTable = context.mLua->newTable();
for (const auto& it : LuaUi::widgetTypeToName())
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 },
{ "Center", LuaUi::Alignment::Center },
{ "End", LuaUi::Alignment::End }

@ -84,12 +84,22 @@ namespace LuaUtil
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)
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
end
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
end
local function nextForArray(array, index)
@ -136,7 +146,7 @@ namespace LuaUtil
mSandboxEnv = sol::nil;
}
sol::table makeReadOnly(sol::table table)
sol::table makeReadOnly(const sol::table& table, bool strictIndex)
{
if (table == sol::nil)
return table;
@ -146,7 +156,11 @@ namespace LuaUtil
lua_State* luaState = table.lua_state();
sol::state_view lua(luaState);
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["__ipairs"] = lua["ipairsForReadOnly"];
@ -158,7 +172,7 @@ namespace LuaUtil
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)

@ -139,7 +139,9 @@ namespace LuaUtil
// 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.
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&);
}

@ -214,7 +214,8 @@ namespace LuaUtil
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'
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)
{

@ -25,6 +25,12 @@
-- @param #table table Any table.
-- @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.
-- @function [parent=#util] loadCode

Loading…
Cancel
Save