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)
|
||||
return self.func
|
||||
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
|
||||
|
|
|
|||
|
|
@ -306,6 +306,22 @@ Node = class {
|
|||
binser.register(self, self.type)
|
||||
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,
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
-- TODO: upstream
|
||||
|
||||
-- binser.lua
|
||||
|
||||
--[[
|
||||
|
|
@ -39,6 +41,8 @@ local floor = math.floor
|
|||
local frexp = math.frexp
|
||||
local unpack = unpack or table.unpack
|
||||
local huge = math.huge
|
||||
local getupvalue = debug.getupvalue
|
||||
local setupvalue = debug.setupvalue
|
||||
|
||||
-- Lua 5.3 frexp polyfill
|
||||
-- From https://github.com/excessive/cpml/blob/master/modules/utils.lua
|
||||
|
|
@ -220,6 +224,7 @@ local function newbinser()
|
|||
-- RESOURCE = 211
|
||||
-- INT64 = 212
|
||||
-- TABLE WITH META = 213
|
||||
-- FUNCTION WITH UPVALUES = 214
|
||||
|
||||
local mts = {}
|
||||
local ids = {}
|
||||
|
|
@ -342,9 +347,19 @@ local function newbinser()
|
|||
visited[x] = visited[NEXT]
|
||||
visited[NEXT] = visited[NEXT] + 1
|
||||
local str = dump(x)
|
||||
accum[#accum + 1] = "\210"
|
||||
accum[#accum + 1] = "\214"
|
||||
accum[#accum + 1] = number_to_str(#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
|
||||
|
||||
|
|
@ -433,13 +448,26 @@ local function newbinser()
|
|||
local ret = deserializers[name](unpack(args))
|
||||
visited[#visited + 1] = ret
|
||||
return ret, nextindex
|
||||
elseif t == 210 then
|
||||
elseif t == 210 or t == 214 then
|
||||
local length, dataindex = number_from_str(str, index + 1)
|
||||
local nextindex = dataindex + length
|
||||
if not (length >= 0) then error("Bad string length") end
|
||||
if #str < nextindex - 1 then error("Expected more bytes of string") end
|
||||
local ret = loadstring(sub(str, dataindex, nextindex - 1))
|
||||
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
|
||||
elseif t == 211 then
|
||||
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 assert0 = require("anselme.common").assert0
|
||||
local anselme
|
||||
local Identifier, Return
|
||||
local Identifier, Return, Node
|
||||
|
||||
local State
|
||||
State = class {
|
||||
|
|
@ -114,19 +114,15 @@ State = class {
|
|||
-- This can be loaded back later using `:load`.
|
||||
save = function(self)
|
||||
local struct = persistent_manager:get_struct(self)
|
||||
package.loaded["anselme.serializer_state"] = self
|
||||
local r = binser.serialize(anselme.versions.save, struct)
|
||||
package.loaded["anselme.serializer_state"] = nil
|
||||
return r
|
||||
return binser.serialize(anselme.versions.save) .. struct:serialize(self)
|
||||
end,
|
||||
--- Load a string generated by `:save`.
|
||||
--
|
||||
-- Variables that already exist will be overwritten with the loaded data.
|
||||
load = function(self, save)
|
||||
package.loaded["anselme.serializer_state"] = self
|
||||
local version, struct = binser.deserializeN(save, 2)
|
||||
package.loaded["anselme.serializer_state"] = nil
|
||||
local version, nextindex = binser.deserializeN(save, 1)
|
||||
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
|
||||
persistent_manager:set(self, key, val)
|
||||
end
|
||||
|
|
@ -246,6 +242,6 @@ State = class {
|
|||
package.loaded[...] = State
|
||||
anselme = require("anselme")
|
||||
local ast = require("anselme.ast")
|
||||
Identifier, Return = ast.Identifier, ast.Return
|
||||
Identifier, Return, Node = ast.Identifier, ast.Return, ast.abstract.Node
|
||||
|
||||
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)
|
||||
write_output("--# main script #--")
|
||||
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()
|
||||
|
||||
|
|
|
|||
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