fix: add lua 5.0 compatibility shims
This commit is contained in:
@@ -19,6 +19,111 @@ if not math.mod then
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Shim for Lua 5.0 where the bit library may be missing.
|
||||||
|
-- Questie uses band/bor/bxor/lshift/rshift in core runtime code, so we provide
|
||||||
|
-- a pure-Lua fallback when the host does not expose one.
|
||||||
|
if not bit or not bit.band or not bit.bor or not bit.bxor or not bit.lshift or not bit.rshift then
|
||||||
|
local bitlib = bit or {}
|
||||||
|
local U32 = 4294967296
|
||||||
|
local U32_MAX = 4294967295
|
||||||
|
local floor = math.floor
|
||||||
|
local mod = math.mod or function(a, b)
|
||||||
|
return a - floor(a / b) * b
|
||||||
|
end
|
||||||
|
|
||||||
|
local function normalizeU32(n)
|
||||||
|
n = tonumber(n) or 0
|
||||||
|
n = floor(n)
|
||||||
|
if n < 0 then
|
||||||
|
n = U32 + mod(n, U32)
|
||||||
|
elseif n >= U32 then
|
||||||
|
n = mod(n, U32)
|
||||||
|
end
|
||||||
|
return n
|
||||||
|
end
|
||||||
|
|
||||||
|
local function bitAt(n, mask)
|
||||||
|
return mod(floor(n / mask), 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function band32(a, b)
|
||||||
|
a = normalizeU32(a)
|
||||||
|
b = normalizeU32(b)
|
||||||
|
local result = 0
|
||||||
|
local mask = 1
|
||||||
|
for _ = 1, 32 do
|
||||||
|
if bitAt(a, mask) == 1 and bitAt(b, mask) == 1 then
|
||||||
|
result = result + mask
|
||||||
|
end
|
||||||
|
mask = mask * 2
|
||||||
|
end
|
||||||
|
return normalizeU32(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function bor32(a, b)
|
||||||
|
a = normalizeU32(a)
|
||||||
|
b = normalizeU32(b)
|
||||||
|
local result = 0
|
||||||
|
local mask = 1
|
||||||
|
for _ = 1, 32 do
|
||||||
|
if bitAt(a, mask) == 1 or bitAt(b, mask) == 1 then
|
||||||
|
result = result + mask
|
||||||
|
end
|
||||||
|
mask = mask * 2
|
||||||
|
end
|
||||||
|
return normalizeU32(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function bxor32(a, b)
|
||||||
|
a = normalizeU32(a)
|
||||||
|
b = normalizeU32(b)
|
||||||
|
local result = 0
|
||||||
|
local mask = 1
|
||||||
|
for _ = 1, 32 do
|
||||||
|
if bitAt(a, mask) ~= bitAt(b, mask) then
|
||||||
|
result = result + mask
|
||||||
|
end
|
||||||
|
mask = mask * 2
|
||||||
|
end
|
||||||
|
return normalizeU32(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function lshift32(a, disp)
|
||||||
|
a = normalizeU32(a)
|
||||||
|
disp = tonumber(disp) or 0
|
||||||
|
if disp <= 0 then
|
||||||
|
return normalizeU32(math.floor(a / (2 ^ (-disp))))
|
||||||
|
elseif disp >= 32 then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
return normalizeU32(a * (2 ^ disp))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function rshift32(a, disp)
|
||||||
|
a = normalizeU32(a)
|
||||||
|
disp = tonumber(disp) or 0
|
||||||
|
if disp <= 0 then
|
||||||
|
return normalizeU32(a * (2 ^ (-disp)))
|
||||||
|
elseif disp >= 32 then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
return normalizeU32(floor(a / (2 ^ disp)))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function bnot32(a)
|
||||||
|
return normalizeU32(U32_MAX - normalizeU32(a))
|
||||||
|
end
|
||||||
|
|
||||||
|
bitlib.band = bitlib.band or band32
|
||||||
|
bitlib.bor = bitlib.bor or bor32
|
||||||
|
bitlib.bxor = bitlib.bxor or bxor32
|
||||||
|
bitlib.lshift = bitlib.lshift or lshift32
|
||||||
|
bitlib.rshift = bitlib.rshift or rshift32
|
||||||
|
bitlib.bnot = bitlib.bnot or bnot32
|
||||||
|
bit = bitlib
|
||||||
|
_G.bit = bitlib
|
||||||
|
end
|
||||||
|
|
||||||
-- Shim for Lua 5.0 where string.match is missing.
|
-- Shim for Lua 5.0 where string.match is missing.
|
||||||
-- Supports up to 5 captures (sufficient for all Questie uses).
|
-- Supports up to 5 captures (sufficient for all Questie uses).
|
||||||
if not string.match then
|
if not string.match then
|
||||||
@@ -57,6 +162,44 @@ if not select then
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Shim for Lua 5.0 where strsplit is missing.
|
||||||
|
if not strsplit then
|
||||||
|
strsplit = function(separator, text, max)
|
||||||
|
if text == nil then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if separator == "" then
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
|
local results = {}
|
||||||
|
local resultCount = 0
|
||||||
|
local startPos = 1
|
||||||
|
local maxSplits = tonumber(max)
|
||||||
|
|
||||||
|
while true do
|
||||||
|
if maxSplits and resultCount >= (maxSplits - 1) then
|
||||||
|
resultCount = resultCount + 1
|
||||||
|
results[resultCount] = string.sub(text, startPos)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
local sepStart, sepEnd = string.find(text, separator, startPos, true)
|
||||||
|
if not sepStart then
|
||||||
|
resultCount = resultCount + 1
|
||||||
|
results[resultCount] = string.sub(text, startPos)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
resultCount = resultCount + 1
|
||||||
|
results[resultCount] = string.sub(text, startPos, sepStart - 1)
|
||||||
|
startPos = sepEnd + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
return unpack(results, 1, resultCount)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- The only public class except for Questie
|
-- The only public class except for Questie
|
||||||
---@class QuestieLoader
|
---@class QuestieLoader
|
||||||
QuestieLoader = QuestieLoader or {}
|
QuestieLoader = QuestieLoader or {}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ local QuestieSerializer = QuestieLoader:CreateModule("QuestieSerializer");
|
|||||||
---@type QuestieStreamLib
|
---@type QuestieStreamLib
|
||||||
local QuestieStreamLib = QuestieLoader:ImportModule("QuestieStreamLib");
|
local QuestieStreamLib = QuestieLoader:ImportModule("QuestieStreamLib");
|
||||||
|
|
||||||
|
local mod = math.mod
|
||||||
|
|
||||||
|
|
||||||
function QuestieSerializer:Hash(value)
|
function QuestieSerializer:Hash(value)
|
||||||
if not value or type(value) ~= "string" or (string.len(value) <= 0) then
|
if not value or type(value) ~= "string" or (string.len(value) <= 0) then
|
||||||
@@ -70,14 +72,14 @@ local function floatBitsToInt(n)
|
|||||||
else
|
else
|
||||||
expo = expo + 0x7E
|
expo = expo + 0x7E
|
||||||
mant = floor((mant * 2.0 - 1.0) * ldexp(0.5, 24))
|
mant = floor((mant * 2.0 - 1.0) * ldexp(0.5, 24))
|
||||||
return _pack(sign + floor(expo / 0x2), (expo % 0x2) * 0x80 + floor(mant / 0x10000), floor(mant / 0x100) % 0x100, mant % 0x100)
|
return _pack(sign + floor(expo / 0x2), mod(expo, 0x2) * 0x80 + floor(mant / 0x10000), mod(floor(mant / 0x100), 0x100), mod(mant, 0x100))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local function intBitsToFloat(int)
|
local function intBitsToFloat(int)
|
||||||
local b1, b2, b3, b4 = _unpack(int)
|
local b1, b2, b3, b4 = _unpack(int)
|
||||||
local sign = b1 > 0x7F
|
local sign = b1 > 0x7F
|
||||||
local expo = (b1 % 0x80) * 0x2 + floor(b2 / 0x80)
|
local expo = mod(b1, 0x80) * 0x2 + floor(b2 / 0x80)
|
||||||
local mant = ((b2 % 0x80) * 0x100 + b3) * 0x100 + b4
|
local mant = ((mod(b2, 0x80)) * 0x100 + b3) * 0x100 + b4
|
||||||
if sign then
|
if sign then
|
||||||
sign = -1
|
sign = -1
|
||||||
else
|
else
|
||||||
|
|||||||
+25
-24
@@ -10,6 +10,7 @@ local unpack_limit = 4096 -- wow api limits unpack to somewhere between 7000-800
|
|||||||
local band = bit.band
|
local band = bit.band
|
||||||
local lshift = bit.lshift
|
local lshift = bit.lshift
|
||||||
local rshift = bit.rshift
|
local rshift = bit.rshift
|
||||||
|
local mod = math.mod
|
||||||
local stringchar = string.char
|
local stringchar = string.char
|
||||||
local stringbyte = string.byte
|
local stringbyte = string.byte
|
||||||
local stringsub = string.sub
|
local stringsub = string.sub
|
||||||
@@ -128,7 +129,7 @@ end
|
|||||||
function QuestieStreamLib:_writeByte(val)
|
function QuestieStreamLib:_writeByte(val)
|
||||||
local p = self._pointer
|
local p = self._pointer
|
||||||
local chunkId = math.floor((p - 1) / 100000) + 1
|
local chunkId = math.floor((p - 1) / 100000) + 1
|
||||||
local localIdx = ((p - 1) % 100000) + 1
|
local localIdx = mod(p - 1, 100000) + 1
|
||||||
|
|
||||||
if not self._bin[chunkId] then
|
if not self._bin[chunkId] then
|
||||||
self._bin[chunkId] = {}
|
self._bin[chunkId] = {}
|
||||||
@@ -152,7 +153,7 @@ function QuestieStreamLib:_readByte()
|
|||||||
return stringbyte(self._bin, p)
|
return stringbyte(self._bin, p)
|
||||||
else
|
else
|
||||||
local chunkId = math.floor((p - 1) / 100000) + 1
|
local chunkId = math.floor((p - 1) / 100000) + 1
|
||||||
local localIdx = ((p - 1) % 100000) + 1
|
local localIdx = mod(p - 1, 100000) + 1
|
||||||
if self._bin[chunkId] then
|
if self._bin[chunkId] then
|
||||||
return stringbyte(self._bin[chunkId][localIdx] or "\0")
|
return stringbyte(self._bin[chunkId][localIdx] or "\0")
|
||||||
end
|
end
|
||||||
@@ -184,7 +185,7 @@ function QuestieStreamLib:_WriteByte_b89(e)
|
|||||||
self._level = level
|
self._level = level
|
||||||
self:_writeByte(QSL_ltab[level])
|
self:_writeByte(QSL_ltab[level])
|
||||||
end
|
end
|
||||||
local chr = (e % 86) + 33
|
local chr = mod(e, 86) + 33
|
||||||
if QSL_ttab[chr] then
|
if QSL_ttab[chr] then
|
||||||
self:_writeByte(QSL_ttab[chr])
|
self:_writeByte(QSL_ttab[chr])
|
||||||
else
|
else
|
||||||
@@ -267,7 +268,7 @@ function QuestieStreamLib:_ReadInt12Pair_raw()
|
|||||||
local p = self._pointer
|
local p = self._pointer
|
||||||
self._pointer = p + 3
|
self._pointer = p + 3
|
||||||
local a,b,c = stringbyte(self._bin, p, p+2)
|
local a,b,c = stringbyte(self._bin, p, p+2)
|
||||||
local low4bit = a % 16
|
local low4bit = mod(a, 16)
|
||||||
return low4bit * 256 + b, (a - low4bit) * 16 + c
|
return low4bit * 256 + b, (a - low4bit) * 16 + c
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -372,8 +373,8 @@ end
|
|||||||
|
|
||||||
function QuestieStreamLib:_WriteShort(val)
|
function QuestieStreamLib:_WriteShort(val)
|
||||||
--print("wshort: " .. val);
|
--print("wshort: " .. val);
|
||||||
self:WriteByte(rshift(val, 8) % 256);
|
self:WriteByte(mod(rshift(val, 8), 256));
|
||||||
self:WriteByte(val % 256);
|
self:WriteByte(mod(val, 256));
|
||||||
end
|
end
|
||||||
|
|
||||||
function QuestieStreamLib:_WriteShort_assert(val)
|
function QuestieStreamLib:_WriteShort_assert(val)
|
||||||
@@ -384,10 +385,10 @@ function QuestieStreamLib:_WriteShort_assert(val)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function QuestieStreamLib:_WriteInt(val)
|
function QuestieStreamLib:_WriteInt(val)
|
||||||
self:WriteByte(rshift(val, 24) % 256);
|
self:WriteByte(mod(rshift(val, 24), 256));
|
||||||
self:WriteByte(rshift(val, 16) % 256);
|
self:WriteByte(mod(rshift(val, 16), 256));
|
||||||
self:WriteByte(rshift(val, 8) % 256);
|
self:WriteByte(mod(rshift(val, 8), 256));
|
||||||
self:WriteByte(val % 256);
|
self:WriteByte(mod(val, 256));
|
||||||
end
|
end
|
||||||
|
|
||||||
function QuestieStreamLib:_WriteInt_assert(val)
|
function QuestieStreamLib:_WriteInt_assert(val)
|
||||||
@@ -399,9 +400,9 @@ end
|
|||||||
|
|
||||||
function QuestieStreamLib:_WriteInt24(val)
|
function QuestieStreamLib:_WriteInt24(val)
|
||||||
--print("wi24: " .. val);
|
--print("wi24: " .. val);
|
||||||
self:WriteByte(rshift(val, 16) % 256);
|
self:WriteByte(mod(rshift(val, 16), 256));
|
||||||
self:WriteByte(rshift(val, 8) % 256);
|
self:WriteByte(mod(rshift(val, 8), 256));
|
||||||
self:WriteByte(val % 256);
|
self:WriteByte(mod(val, 256));
|
||||||
end
|
end
|
||||||
|
|
||||||
function QuestieStreamLib:_WriteInt24_assert(val)
|
function QuestieStreamLib:_WriteInt24_assert(val)
|
||||||
@@ -413,8 +414,8 @@ end
|
|||||||
|
|
||||||
function QuestieStreamLib:_WriteInt12Pair(val1, val2)
|
function QuestieStreamLib:_WriteInt12Pair(val1, val2)
|
||||||
self:WriteByte(band(rshift(val1, 8), 15) + lshift(band(rshift(val2, 8), 15), 4))
|
self:WriteByte(band(rshift(val1, 8), 15) + lshift(band(rshift(val2, 8), 15), 4))
|
||||||
self:WriteByte(val1 % 256)
|
self:WriteByte(mod(val1, 256))
|
||||||
self:WriteByte(val2 % 256)
|
self:WriteByte(mod(val2, 256))
|
||||||
end
|
end
|
||||||
|
|
||||||
function QuestieStreamLib:_WriteInt12Pair_assert(val1, val2)
|
function QuestieStreamLib:_WriteInt12Pair_assert(val1, val2)
|
||||||
@@ -430,14 +431,14 @@ function QuestieStreamLib:_WriteInt12Pair_assert(val1, val2)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function QuestieStreamLib:_WriteLong(val)
|
function QuestieStreamLib:_WriteLong(val)
|
||||||
self:WriteByte(rshift(val, 56) % 256);
|
self:WriteByte(mod(rshift(val, 56), 256));
|
||||||
self:WriteByte(rshift(val, 48) % 256);
|
self:WriteByte(mod(rshift(val, 48), 256));
|
||||||
self:WriteByte(rshift(val, 40) % 256);
|
self:WriteByte(mod(rshift(val, 40), 256));
|
||||||
self:WriteByte(rshift(val, 32) % 256);
|
self:WriteByte(mod(rshift(val, 32), 256));
|
||||||
self:WriteByte(rshift(val, 24) % 256);
|
self:WriteByte(mod(rshift(val, 24), 256));
|
||||||
self:WriteByte(rshift(val, 16) % 256);
|
self:WriteByte(mod(rshift(val, 16), 256));
|
||||||
self:WriteByte(rshift(val, 8) % 256);
|
self:WriteByte(mod(rshift(val, 8), 256));
|
||||||
self:WriteByte(val % 256);
|
self:WriteByte(mod(val, 256));
|
||||||
end
|
end
|
||||||
|
|
||||||
function QuestieStreamLib:_WriteLong_assert(val)
|
function QuestieStreamLib:_WriteLong_assert(val)
|
||||||
@@ -476,7 +477,7 @@ end
|
|||||||
|
|
||||||
function QuestieStreamLib:Save()
|
function QuestieStreamLib:Save()
|
||||||
local chunks = {}
|
local chunks = {}
|
||||||
for i=1, #self._bin do
|
for i=1, table.getn(self._bin) do
|
||||||
table.insert(chunks, table.concat(self._bin[i]))
|
table.insert(chunks, table.concat(self._bin[i]))
|
||||||
end
|
end
|
||||||
return table.concat(chunks)
|
return table.concat(chunks)
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ describe("Audit Pass 9 - file-by-file findings (snapshot at HEAD)", function()
|
|||||||
it("[9.1->11.1] CORRECTED: % modulo IS used (the 'avoided' claim was wrong)", function()
|
it("[9.1->11.1] CORRECTED: % modulo IS used (the 'avoided' claim was wrong)", function()
|
||||||
-- Pass 8-10 wrongly said % modulo = 0. Real modulo operators exist in
|
-- Pass 8-10 wrongly said % modulo = 0. Real modulo operators exist in
|
||||||
-- Turtle-TOC files and are 5.0 parse errors that math.mod cannot rescue.
|
-- Turtle-TOC files and are 5.0 parse errors that math.mod cannot rescue.
|
||||||
assert.is_true(has(read("Modules/QuestieStream.lua"), " % 256"))
|
assert.is_true(has(read("Modules/QuestieStream.lua"), "mod(val, 256)"))
|
||||||
assert.is_true(has(read("Modules/QuestiePlayer.lua"), "% playerRaceFlagX2"))
|
assert.is_true(has(read("Modules/QuestiePlayer.lua"), "% playerRaceFlagX2"))
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
@@ -326,4 +326,25 @@ describe("Audit Pass 10 - additional performance findings (snapshot)", function(
|
|||||||
assert.is_true(has(advancedOptions, "questieCommsQuestListBlockInterval"))
|
assert.is_true(has(advancedOptions, "questieCommsQuestListBlockInterval"))
|
||||||
assert.is_true(has(advancedOptions, "Questie.db.profile.questieCommsEnabled == false"))
|
assert.is_true(has(advancedOptions, "Questie.db.profile.questieCommsEnabled == false"))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it("[L50] loader, serializer, and stream are wired for Lua 5.0 compatibility", function()
|
||||||
|
local loader = read("Modules/Libs/QuestieLoader.lua")
|
||||||
|
local serializer = read("Modules/Libs/QuestieSerializer.lua")
|
||||||
|
local stream = read("Modules/QuestieStream.lua")
|
||||||
|
|
||||||
|
assert.is_true(has(loader, "bitlib.band = bitlib.band or band32"))
|
||||||
|
assert.is_true(has(loader, "strsplit = function(separator, text, max)"))
|
||||||
|
|
||||||
|
assert.is_true(has(serializer, "local mod = math.mod"))
|
||||||
|
assert.is_true(has(serializer, "mod(expo, 0x2)"))
|
||||||
|
assert.is_true(has(serializer, "mod(b1, 0x80)"))
|
||||||
|
assert.is_false(has(serializer, "expo % 0x2"))
|
||||||
|
|
||||||
|
assert.is_true(has(stream, "local mod = math.mod"))
|
||||||
|
assert.is_true(has(stream, "table.getn(self._bin)"))
|
||||||
|
assert.is_true(has(stream, "mod(val1, 256)"))
|
||||||
|
assert.is_true(has(stream, "mod(val2, 256)"))
|
||||||
|
assert.is_false(has(stream, "val1 % 256"))
|
||||||
|
assert.is_false(has(stream, "val2 % 256"))
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|||||||
Reference in New Issue
Block a user