summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server/src/vm/function.lua45
-rw-r--r--server/src/vm/vm.lua28
-rw-r--r--server/test/diagnostics/init.lua12
3 files changed, 77 insertions, 8 deletions
diff --git a/server/src/vm/function.lua b/server/src/vm/function.lua
index 9dcc1f02..20a5c75b 100644
--- a/server/src/vm/function.lua
+++ b/server/src/vm/function.lua
@@ -21,7 +21,7 @@ function mt:getUri()
return source and source.uri or ''
end
-function mt:push(source)
+function mt:push(source, ischunk)
if self._removed then
return
end
@@ -30,6 +30,10 @@ function mt:push(source)
self.finishs[self._top] = source and source.finish or math.maxinteger
end
+function mt:markChunk()
+ self.chunk[self._top] = true
+end
+
function mt:pop()
if self._removed then
return
@@ -37,6 +41,7 @@ function mt:pop()
local closed = self.finishs[self._top]
local closedLocals = self.locals[self._top]
self.locals[self._top] = nil
+ self.chunk[self._top] = nil
for _, loc in pairs(closedLocals) do
loc:close(closed)
end
@@ -57,6 +62,16 @@ function mt:saveLocal(name, loc)
self.locals[self._top][name] = loc
end
+function mt:saveUpvalue(name, loc)
+ if self._removed then
+ return
+ end
+ if loc.type ~= 'local' then
+ error('saveLocal必须是local')
+ end
+ self.upvalues[name] = loc
+end
+
function mt:loadLocal(name)
for i = self._top, 1, -1 do
local locals = self.locals[i]
@@ -64,6 +79,13 @@ function mt:loadLocal(name)
if loc then
return loc
end
+ if self.chunk[i] then
+ break
+ end
+ end
+ local uv = self.upvalues[name]
+ if uv then
+ return uv
end
return nil
end
@@ -81,6 +103,18 @@ function mt:eachLocal(callback)
end
end
end
+ if self.chunk[i] then
+ break
+ end
+ end
+ for name, loc in pairs(self.upvalues) do
+ if not mark[name] then
+ mark[name] = true
+ local res = callback(name, loc)
+ if res ~= nil then
+ return res
+ end
+ end
end
return nil
end
@@ -208,7 +242,7 @@ function mt:run(vm)
if self._objectSource then
local loc = localMgr.create('self', vm:instantSource(self._objectSource), self._objectValue)
loc:set('hide', true)
- self:saveLocal('self', loc)
+ self:saveUpvalue('self', loc)
self.args[#self.args+1] = loc
end
@@ -246,7 +280,7 @@ function mt:createArg(vm, arg)
arg:set('arg', true)
if arg.type == 'name' then
local loc = localMgr.create(arg[1], arg, valueMgr.create('nil', arg))
- self:saveLocal(arg[1], loc)
+ self:saveUpvalue(arg[1], loc)
self.args[#self.args+1] = loc
elseif arg.type == '...' then
self._dots = createMulti()
@@ -259,7 +293,7 @@ function mt:createLibArg(arg, source)
else
local name = arg.name or '_'
local loc = localMgr.create(name, source, valueMgr.create('any', source))
- self:saveLocal(name, loc)
+ self:saveUpvalue(name, loc)
self.args[#self.args+1] = loc
end
end
@@ -337,11 +371,12 @@ local function create(source)
local self = setmetatable({
source = id,
locals = {},
+ upvalues = {},
+ chunk = {},
finishs = {},
args = {},
argValues = {},
}, mt)
- self:push(source)
local id = listMgr.add(self)
self.id = id
diff --git a/server/src/vm/vm.lua b/server/src/vm/vm.lua
index ef3ce27b..c9bc396c 100644
--- a/server/src/vm/vm.lua
+++ b/server/src/vm/vm.lua
@@ -103,6 +103,7 @@ function mt:runFunction(func)
local originFunction = self:getCurrentFunction()
self:setCurrentFunction(func)
func:push(func:getSource())
+ func:markChunk()
self:doActions(func:getSource())
@@ -125,7 +126,7 @@ function mt:buildFunction(exp)
local func = value:getFunction()
self:eachLocal(function (name, loc)
- func:saveLocal(name, loc)
+ func:saveUpvalue(name, loc)
end)
return value
@@ -1078,6 +1079,10 @@ function mt:saveLocal(name, loc)
self.currentFunction:saveLocal(name, loc)
end
+function mt:saveUpvalue(name, loc)
+ self.currentFunction:saveUpvalue(name, loc)
+end
+
function mt:loadLocal(name)
return self.currentFunction:loadLocal(name)
end
@@ -1153,6 +1158,23 @@ function mt:createLocal(key, source, value)
return loc
end
+function mt:createUpvalue(key, source, value)
+ local loc = self:bindLocal(source)
+ if loc then
+ return loc
+ end
+
+ if not value then
+ value = self:createValue('nil', source)
+ end
+
+ loc = localMgr.create(key, source, value)
+ self:saveUpvalue(key, loc)
+ self:bindLocal(source, loc, 'local')
+ value:addInfo('local', source)
+ return loc
+end
+
function mt:createEnvironment(ast)
-- 整个文件是一个函数
self.main = self:createFunction(ast)
@@ -1165,11 +1187,11 @@ function mt:createEnvironment(ast)
local env
if self.envType == '_ENV' then
-- 隐藏的上值`_ENV`
- env = self:createLocal('_ENV', self:getDefaultSource(), global)
+ env = self:createUpvalue('_ENV', self:getDefaultSource(), global)
else
-- 为了实现方便,fenv也使用隐藏上值来实现
-- 使用了非法标识符保证用户无法访问
- env = self:createLocal('@ENV', self:getDefaultSource(), global)
+ env = self:createUpvalue('@ENV', self:getDefaultSource(), global)
end
env:set('hide', true)
self.env = env
diff --git a/server/test/diagnostics/init.lua b/server/test/diagnostics/init.lua
index 9fbe9624..218f0f55 100644
--- a/server/test/diagnostics/init.lua
+++ b/server/test/diagnostics/init.lua
@@ -312,3 +312,15 @@ local _ = 1, <!2!>
TEST [[
_ = 1, <!2!>
]]
+
+TEST [[
+local function x()
+ do
+ local k
+ print(k)
+ x()
+ end
+ local k = 1
+ print(k)
+end
+]]