diff options
-rw-r--r-- | server/src/vm/function.lua | 45 | ||||
-rw-r--r-- | server/src/vm/vm.lua | 28 | ||||
-rw-r--r-- | server/test/diagnostics/init.lua | 12 |
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 +]] |