mirror of
https://github.com/Reuh/anselme.git
synced 2025-10-27 16:49:31 +00:00
Persist LuaFunctions & add tests
This commit is contained in:
parent
a46ac380e8
commit
9a38dfa34f
11 changed files with 108 additions and 19 deletions
|
|
@ -75,14 +75,6 @@ LuaFunction = ast.abstract.Runtime(Overloadable) {
|
||||||
to_lua = function(self, state)
|
to_lua = function(self, state)
|
||||||
return self.func
|
return self.func
|
||||||
end,
|
end,
|
||||||
|
|
||||||
-- TODO: binser does not serialize lua function upvalues!
|
|
||||||
_serialize = function(self)
|
|
||||||
error("LuaFunction can not be serialized")
|
|
||||||
end,
|
|
||||||
_deserialize = function(self)
|
|
||||||
error("LuaFunction can not be serialized")
|
|
||||||
end
|
|
||||||
}
|
}
|
||||||
|
|
||||||
package.loaded[...] = LuaFunction
|
package.loaded[...] = LuaFunction
|
||||||
|
|
|
||||||
|
|
@ -306,6 +306,22 @@ Node = class {
|
||||||
binser.register(self, self.type)
|
binser.register(self, self.type)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
-- return a serialized representation of the node
|
||||||
|
-- can redefine _serialize and _deserialize to customize the serialization, see binser docs
|
||||||
|
serialize = function(self, state)
|
||||||
|
package.loaded["anselme.serializer_state"] = state
|
||||||
|
local r = binser.serialize(self)
|
||||||
|
package.loaded["anselme.serializer_state"] = nil
|
||||||
|
return r
|
||||||
|
end,
|
||||||
|
-- return the deserialized Node
|
||||||
|
-- class method
|
||||||
|
deserialize = function(self, state, str, index)
|
||||||
|
package.loaded["anselme.serializer_state"] = state
|
||||||
|
local r = binser.deserializeN(str, 1, index)
|
||||||
|
package.loaded["anselme.serializer_state"] = nil
|
||||||
|
return r
|
||||||
|
end,
|
||||||
|
|
||||||
__tostring = function(self) return self:format() end,
|
__tostring = function(self) return self:format() end,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
-- TODO: upstream
|
||||||
|
|
||||||
-- binser.lua
|
-- binser.lua
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
|
|
@ -39,6 +41,8 @@ local floor = math.floor
|
||||||
local frexp = math.frexp
|
local frexp = math.frexp
|
||||||
local unpack = unpack or table.unpack
|
local unpack = unpack or table.unpack
|
||||||
local huge = math.huge
|
local huge = math.huge
|
||||||
|
local getupvalue = debug.getupvalue
|
||||||
|
local setupvalue = debug.setupvalue
|
||||||
|
|
||||||
-- Lua 5.3 frexp polyfill
|
-- Lua 5.3 frexp polyfill
|
||||||
-- From https://github.com/excessive/cpml/blob/master/modules/utils.lua
|
-- From https://github.com/excessive/cpml/blob/master/modules/utils.lua
|
||||||
|
|
@ -220,6 +224,7 @@ local function newbinser()
|
||||||
-- RESOURCE = 211
|
-- RESOURCE = 211
|
||||||
-- INT64 = 212
|
-- INT64 = 212
|
||||||
-- TABLE WITH META = 213
|
-- TABLE WITH META = 213
|
||||||
|
-- FUNCTION WITH UPVALUES = 214
|
||||||
|
|
||||||
local mts = {}
|
local mts = {}
|
||||||
local ids = {}
|
local ids = {}
|
||||||
|
|
@ -342,9 +347,19 @@ local function newbinser()
|
||||||
visited[x] = visited[NEXT]
|
visited[x] = visited[NEXT]
|
||||||
visited[NEXT] = visited[NEXT] + 1
|
visited[NEXT] = visited[NEXT] + 1
|
||||||
local str = dump(x)
|
local str = dump(x)
|
||||||
accum[#accum + 1] = "\210"
|
accum[#accum + 1] = "\214"
|
||||||
accum[#accum + 1] = number_to_str(#str)
|
accum[#accum + 1] = number_to_str(#str)
|
||||||
accum[#accum + 1] = str
|
accum[#accum + 1] = str
|
||||||
|
local upvalues = {}
|
||||||
|
local i = 1
|
||||||
|
repeat
|
||||||
|
local name, value = getupvalue(x, i)
|
||||||
|
if name and name ~= "_ENV" then
|
||||||
|
upvalues[name] = value
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
until not name
|
||||||
|
types.table(upvalues, visited, accum)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -433,13 +448,26 @@ local function newbinser()
|
||||||
local ret = deserializers[name](unpack(args))
|
local ret = deserializers[name](unpack(args))
|
||||||
visited[#visited + 1] = ret
|
visited[#visited + 1] = ret
|
||||||
return ret, nextindex
|
return ret, nextindex
|
||||||
elseif t == 210 then
|
elseif t == 210 or t == 214 then
|
||||||
local length, dataindex = number_from_str(str, index + 1)
|
local length, dataindex = number_from_str(str, index + 1)
|
||||||
local nextindex = dataindex + length
|
local nextindex = dataindex + length
|
||||||
if not (length >= 0) then error("Bad string length") end
|
if not (length >= 0) then error("Bad string length") end
|
||||||
if #str < nextindex - 1 then error("Expected more bytes of string") end
|
if #str < nextindex - 1 then error("Expected more bytes of string") end
|
||||||
local ret = loadstring(sub(str, dataindex, nextindex - 1))
|
local ret = loadstring(sub(str, dataindex, nextindex - 1))
|
||||||
visited[#visited + 1] = ret
|
visited[#visited + 1] = ret
|
||||||
|
if t == 214 then
|
||||||
|
local upvalues
|
||||||
|
upvalues, nextindex = deserialize_value(str, nextindex, visited)
|
||||||
|
if type(upvalues) ~= "table" then error("Expected function upvalues") end
|
||||||
|
local i = 1
|
||||||
|
repeat
|
||||||
|
local name = getupvalue(ret, i)
|
||||||
|
if name and upvalues[name] ~= nil then
|
||||||
|
setupvalue(ret, i, upvalues[name])
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
until not name
|
||||||
|
end
|
||||||
return ret, nextindex
|
return ret, nextindex
|
||||||
elseif t == 211 then
|
elseif t == 211 then
|
||||||
local resname, nextindex = deserialize_value(str, index + 1, visited)
|
local resname, nextindex = deserialize_value(str, index + 1, visited)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ local parser = require("anselme.parser")
|
||||||
local binser = require("anselme.lib.binser")
|
local binser = require("anselme.lib.binser")
|
||||||
local assert0 = require("anselme.common").assert0
|
local assert0 = require("anselme.common").assert0
|
||||||
local anselme
|
local anselme
|
||||||
local Identifier, Return
|
local Identifier, Return, Node
|
||||||
|
|
||||||
local State
|
local State
|
||||||
State = class {
|
State = class {
|
||||||
|
|
@ -114,19 +114,15 @@ State = class {
|
||||||
-- This can be loaded back later using `:load`.
|
-- This can be loaded back later using `:load`.
|
||||||
save = function(self)
|
save = function(self)
|
||||||
local struct = persistent_manager:get_struct(self)
|
local struct = persistent_manager:get_struct(self)
|
||||||
package.loaded["anselme.serializer_state"] = self
|
return binser.serialize(anselme.versions.save) .. struct:serialize(self)
|
||||||
local r = binser.serialize(anselme.versions.save, struct)
|
|
||||||
package.loaded["anselme.serializer_state"] = nil
|
|
||||||
return r
|
|
||||||
end,
|
end,
|
||||||
--- Load a string generated by `:save`.
|
--- Load a string generated by `:save`.
|
||||||
--
|
--
|
||||||
-- Variables that already exist will be overwritten with the loaded data.
|
-- Variables that already exist will be overwritten with the loaded data.
|
||||||
load = function(self, save)
|
load = function(self, save)
|
||||||
package.loaded["anselme.serializer_state"] = self
|
local version, nextindex = binser.deserializeN(save, 1)
|
||||||
local version, struct = binser.deserializeN(save, 2)
|
|
||||||
package.loaded["anselme.serializer_state"] = nil
|
|
||||||
if version ~= anselme.versions.save then print("Loading a save file generated by a different Anselme version, things may break!") end
|
if version ~= anselme.versions.save then print("Loading a save file generated by a different Anselme version, things may break!") end
|
||||||
|
local struct = Node:deserialize(self, save, nextindex)
|
||||||
for key, val in struct:iter() do
|
for key, val in struct:iter() do
|
||||||
persistent_manager:set(self, key, val)
|
persistent_manager:set(self, key, val)
|
||||||
end
|
end
|
||||||
|
|
@ -246,6 +242,6 @@ State = class {
|
||||||
package.loaded[...] = State
|
package.loaded[...] = State
|
||||||
anselme = require("anselme")
|
anselme = require("anselme")
|
||||||
local ast = require("anselme.ast")
|
local ast = require("anselme.ast")
|
||||||
Identifier, Return = ast.Identifier, ast.Return
|
Identifier, Return, Node = ast.Identifier, ast.Return, ast.abstract.Node
|
||||||
|
|
||||||
return State
|
return State
|
||||||
|
|
|
||||||
7
test/results/serialize function.ans
Normal file
7
test/results/serialize function.ans
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
--# run #--
|
||||||
|
--- text ---
|
||||||
|
| {}"" {}"bar1" {}"" |
|
||||||
|
--- return ---
|
||||||
|
()
|
||||||
|
--# saved #--
|
||||||
|
{}
|
||||||
7
test/results/serialize lua function.ans
Normal file
7
test/results/serialize lua function.ans
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
--# run #--
|
||||||
|
--- text ---
|
||||||
|
| {}"" {}"2" {}"" |
|
||||||
|
--- return ---
|
||||||
|
()
|
||||||
|
--# saved #--
|
||||||
|
{}
|
||||||
11
test/results/serialize.ans
Normal file
11
test/results/serialize.ans
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
--# run #--
|
||||||
|
--- text ---
|
||||||
|
| {}"" {}"43" {}"" |
|
||||||
|
--- text ---
|
||||||
|
| {}"" {}"[2, \"\", 5]" {}"" |
|
||||||
|
--- text ---
|
||||||
|
| {}"" {}"*{\"f\":\"b\", 1:2, 2:\"\", 3:\"ok\"}" {}"" |
|
||||||
|
--- return ---
|
||||||
|
()
|
||||||
|
--# saved #--
|
||||||
|
{}
|
||||||
|
|
@ -88,6 +88,8 @@ local function run(path, interactive)
|
||||||
run_loop(parallel_state, write_output, interactive)
|
run_loop(parallel_state, write_output, interactive)
|
||||||
write_output("--# main script #--")
|
write_output("--# main script #--")
|
||||||
end)
|
end)
|
||||||
|
state:define("serialize", "(value)", function(state, value) return ast.String:new(value:serialize(state)) end, true)
|
||||||
|
state:define("deserialize", "(str::string)", function(state, str) return ast.abstract.Node:deserialize(state, str.string) end, true)
|
||||||
|
|
||||||
local run_state = state:branch()
|
local run_state = state:branch()
|
||||||
|
|
||||||
|
|
|
||||||
10
test/tests/serialize function.ans
Normal file
10
test/tests/serialize function.ans
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
:f = ()
|
||||||
|
_
|
||||||
|
:$_+_(a::string, b)
|
||||||
|
"{a}{b}"
|
||||||
|
|
||||||
|
:a=1
|
||||||
|
f = $(x)
|
||||||
|
x+a
|
||||||
|
|
||||||
|
|{(f!serialize!deserialize)("bar")}
|
||||||
7
test/tests/serialize lua function.ans
Normal file
7
test/tests/serialize lua function.ans
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
:f = ()
|
||||||
|
_
|
||||||
|
:a=1
|
||||||
|
f = $()
|
||||||
|
1+a
|
||||||
|
|
||||||
|
|{(f!serialize!deserialize)!}
|
||||||
13
test/tests/serialize.ans
Normal file
13
test/tests/serialize.ans
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
:x = 43
|
||||||
|
|
||||||
|
|{x!serialize!deserialize}
|
||||||
|
|
||||||
|
:l = [2, "", 5]
|
||||||
|
|
||||||
|
|{l!serialize!deserialize}
|
||||||
|
|
||||||
|
:t = *{2, "", 5}
|
||||||
|
t(3) = "ok"
|
||||||
|
t("f") = "b"
|
||||||
|
|
||||||
|
|{t!serialize!deserialize}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue