diff --git a/polymer/eduke32/source/lunatic/defs.ilua b/polymer/eduke32/source/lunatic/defs.ilua index 59fc07bd1..baa076c3d 100644 --- a/polymer/eduke32/source/lunatic/defs.ilua +++ b/polymer/eduke32/source/lunatic/defs.ilua @@ -1,5 +1,5 @@ +-- INTERNAL -- definitions of BUILD and game types for the Lunatic Interpreter --- INTERNAL! local ffi = require("ffi") @@ -567,20 +567,21 @@ function getbunch(sectnum, cf) end +-- gamevarNames[name] is true if that gamevar was declared +local gamevarNames = {} + -- code for prohibiting initial assignments to create new variables, -- based on 14.2 of PiL function gamevar(name, initval) -- aka 'declare' - local declaredNames = {} - if (type(name) ~= "string") then error("First argument to 'gamevar' must be a string", 2); end - if (~string.match(name, "^[%a_][%w_]*$")) then + if (not string.match(name, "^[%a_][%w_]*$")) then error("First argument to 'gamevar' must be a valid identifier", 2); end - if (declaredNames[name]) then + if (gamevarNames[name]) then error(string.format("Duplicate declaration of identifier '%s'", name), 2) end @@ -588,11 +589,90 @@ function gamevar(name, initval) -- aka 'declare' error(string.format("Identifier name '%s' is already used in the global environment", name), 2) end - declaredNames[name] = true + gamevarNames[name] = true rawset(G_, name, initval or false) end +---=== Serialization, from PiL with modifications ===--- +local function basicSerialize(o) + if (type(o) == "number") then + if (o ~= o) then return "0/0" end -- nan + if (o == 1/0) then return "1/0" end -- inf + if (o == -1/0) then return "-1/0" end -- -inf + + return tostring(o) + else -- must be a string + if (type(o) ~= "string") then + error("cannot save a " .. type(o) .. " as key of a table", 3); + end + + return string.format("%q", o) + end +end + +-- will contain all gamevar tables as keys (and true as value) +local tmpgvtabs = {} + +local function save(name, value, saved, strings) + saved = saved or {} -- initial value + + strings[#strings+1] = name .. "=" + + if (type(value) == "number" or type(value) == "string") then + strings[#strings+1] = basicSerialize(value) .. "\n" + elseif (type(value) == "table") then + if (saved[value]) then -- value already saved? + strings[#strings+1] = saved[value] .. "\n" -- use its previous name + else + saved[value] = name -- save name for next time + strings[#strings+1] = "{}\n" -- create a new table + + for k,v in pairs(value) do -- save its fields + local fieldname = string.format("%s[%s]", name, basicSerialize(k)) + if (type(v)=="table" and not tmpgvtabs[v]) then + error("cannot save \""..name.. + "\": gamevar tables may only contain tables that are also gamevars", 2) + end + save(fieldname, v, saved, strings) + end + end + else + error("cannot save \""..name.."\", a " .. type(value), 2) + end +end + +local function serializeGamevars() + local saved = {} + local strings = {} + + for gvname,_ in pairs(gamevarNames) do + if (type(G_[gvname])=="table") then + tmpgvtabs[G_[gvname]] = true + end + end + + -- TODO: catch errors in save() + for gvname,_ in pairs(gamevarNames) do + save(gvname, G_[gvname], saved, strings) + end + strings[#strings+1] = "\n" + + tmpgvtabs = {} + + return table.concat(strings) +end + +local function loadGamevarsString(string) + assert(loadstring(string))() +end + +DBG_.serializeGamevars = serializeGamevars +DBG_.loadGamevarsString = loadGamevarsString + + +---=== Environment setup ===--- + -- add new variables/functions living in the global environment G_.DBG_ = DBG_ -- REMOVE this for release G_.gv = gv diff --git a/polymer/eduke32/source/lunatic/lunacon.lua b/polymer/eduke32/source/lunatic/lunacon.lua index e0c19487c..10242d4de 100644 --- a/polymer/eduke32/source/lunatic/lunacon.lua +++ b/polymer/eduke32/source/lunatic/lunacon.lua @@ -708,7 +708,7 @@ end -- Returns index into the sorted table tab such that -- tab[index] <= searchelt < tab[index+1]. -- Preconditions: --- tab[i] < tab[i+1] for i < i+1 and 1 < i < #tab +-- tab[i] < tab[i+1] for 1 <= i < #tab -- tab[1] <= searchelt < tab[#tab] -- If tab has less than 2 elements, returns nil. local function bsearch(tab, searchelt) diff --git a/polymer/eduke32/source/lunatic/test.elua b/polymer/eduke32/source/lunatic/test.elua index 68f680b82..5bb6e4cbf 100644 --- a/polymer/eduke32/source/lunatic/test.elua +++ b/polymer/eduke32/source/lunatic/test.elua @@ -1,5 +1,7 @@ -- test script for ELua/Lunatic Interpreter +--return + print('--- ELua Test script ---') local function checkfail(funcstr) @@ -11,6 +13,27 @@ local function checkfail(funcstr) end end + +---- check serialization ---- +gamevar("ourvar") +gamevar("ourvar2") + +-- test nans, infs, precision, subnorms +ourvar2 = { "asd"; 0/0, 1/0, -1/0, 0.12345678901234567, 1e-314 } +ourvar = { ourvar2; 1, 2, 3, "qwe" } +ourvar[#ourvar+1] = ourvar; + +local gvstr = DBG_.serializeGamevars() +ourvar = -1 + +print("---------- attempting to load string: ----------") +print(gvstr) +print("---------- (end string to load) ----------") + +DBG_.loadGamevarsString(gvstr) +print("ourvar[4]="..ourvar[4]) + + local i print('tweaking sector pals')