lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Thu, Jan 28, 2010 at 4:09 AM, 刘小凡 <zhqqmao@gmail.com> wrote:
> The origin of the problem is due to the early days of the code often are
> difficult to detect low-level errors, such as spelling errors, simple logic
> error, many of these errors can be reflected only in the run-time. Therefore
> developers may need to restart the server to reload all the scripts, to
> restore its original state, this process is too cumbersome!

That is very clear, and as you say the problem is that dofile() does
not know about the detailed environment of the existing code. There
are often local variables involved, so simply using the environment of
the file (usually just _G, could be a module) won't do.

Here is a little test program where a function with local references
is recompiled successfully:

local x,y = 10,20

function test ()
	return x+y
end

function getlocals (level)
    local i = 1
	local values,indices = {},{}
	while true do
		local name,val = debug.getlocal(level,i)
		if not name then break end
		values[name] = val
		indices[name] = i
		i = i + 1
	end
	return values,indices
end

function recompile (level,str)
	local fn,err = loadstring(str)
	if not fn then return nil,err end
	local locals,locals_idx = getlocals(level)
	local env = {}
	local scope = getfenv(level)
	setmetatable(env,{
		__index = function(tab, key)
			local val = locals[key]
			if val then return val end
			val = scope[key]
			if val then return val end
		end,
		__newindex = function(tab, key, val)
			if locals[key] then
				debug.setlocal(3,locals_idx[key],val)
				locals[key] = val
			else
				scope[key] = val
			end
		end
		})

	fn()
	setfenv(test,env)
end

recompile (3,[[
	function test ()
		x = 30
		glob = 'hello'
		return x*y
	end
	]]
)

print(test(),x,glob)

getlocals() uses the debug API to find all the local variables, names,
values and indexes. We use this to create a special environment for
the function. Any variables in the function will be first looked up in
this locals table, then in the enclosing environment (which is just _G
in this case).  If any locals are _assigned_, then the debug API is
used to actually modify the locals.

Very proof-of-concept, but it does show a way.

steve d.