123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- local debug = debug
- local table = table
- local FUNC_TEMP=[[
- local $ARGS
- return function(...)
- $SOURCE
- end,
- function()
- return {$LOCALS}
- end
- ]]
- local temp = {}
- local function wrap_locals(co, source, level, ext_funcs)
- if co == coroutine.running() then
- level = level + 3
- end
- local f = debug.getinfo(co, level,"f").func
- if f == nil then
- return false, "Invalid level"
- end
- local uv = {}
- local locals = {}
- local uv_id = {}
- local local_id = {}
- if ext_funcs then
- for k,v in pairs(ext_funcs) do
- table.insert(uv, k)
- end
- end
- local i = 1
- while true do
- local name, value = debug.getlocal(co, level, i)
- if name == nil then
- break
- end
- if name:byte() ~= 40 then -- '('
- table.insert(uv, name)
- table.insert(locals, ("[%d]=%s,"):format(i,name))
- local_id[name] = value
- end
- i = i + 1
- end
- local i = 1
- while true do
- local name = debug.getupvalue(f, i)
- if name == nil then
- break
- end
- uv_id[name] = i
- table.insert(uv, name)
- i = i + 1
- end
- temp.ARGS = table.concat(uv, ",")
- temp.SOURCE = source
- temp.LOCALS = table.concat(locals)
- local full_source = FUNC_TEMP:gsub("%$(%w+)",temp)
- local loader, err = load(full_source, "=(debug)")
- if loader == nil then
- return false, err
- end
- local func, update = loader()
- -- join func's upvalues
- local i = 1
- while true do
- local name = debug.getupvalue(func, i)
- if name == nil then
- break
- end
- if ext_funcs then
- local v = ext_funcs[name]
- if v then
- debug.setupvalue(func, i, v)
- end
- end
- local local_value = local_id[name]
- if local_value then
- debug.setupvalue(func, i, local_value)
- end
- local upvalue_id = uv_id[name]
- if upvalue_id then
- debug.upvaluejoin(func, i, f, upvalue_id)
- end
- i=i+1
- end
- local vararg, v = debug.getlocal(co, level, -1)
- if vararg then
- local vargs = { v }
- local i = 2
- while true do
- local vararg,v = debug.getlocal(co, level, -i)
- if vararg then
- vargs[i] = v
- else
- break
- end
- i=i+1
- end
- return func, update, table.unpack(vargs)
- else
- return func, update
- end
- end
- local function exec(co, level, func, update, ...)
- if not func then
- return false, update
- end
- if co == coroutine.running() then
- level = level + 2
- end
- local rets = table.pack(pcall(func, ...))
- if rets[1] then
- local needupdate = update()
- for k,v in pairs(needupdate) do
- debug.setlocal(co, level,k,v)
- end
- return table.unpack(rets, 1, rets.n)
- else
- return false, rets[2]
- end
- end
- return function (source, co, level, ext_funcs)
- co = co or coroutine.running()
- level = level or 0
- return exec(co, level, wrap_locals(co, source, level, ext_funcs))
- end
|