diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2019-11-22 23:26:32 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2019-11-22 23:26:32 +0800 |
commit | d0ff66c9abe9d6abbca12fd811e0c3cb69c1033a (patch) | |
tree | bb34518d70b85de7656dbdbe958dfa221a3ff3b3 /server/src/vm | |
parent | 0a2c2ad15e1ec359171fb0dd4c72e57c5b66e9ba (diff) | |
download | lua-language-server-d0ff66c9abe9d6abbca12fd811e0c3cb69c1033a.zip |
整理一下目录结构
Diffstat (limited to 'server/src/vm')
-rw-r--r-- | server/src/vm/chain.lua | 65 | ||||
-rw-r--r-- | server/src/vm/emmy.lua | 372 | ||||
-rw-r--r-- | server/src/vm/function.lua | 551 | ||||
-rw-r--r-- | server/src/vm/global.lua | 25 | ||||
-rw-r--r-- | server/src/vm/init.lua | 1 | ||||
-rw-r--r-- | server/src/vm/ipairs.lua | 51 | ||||
-rw-r--r-- | server/src/vm/label.lua | 75 | ||||
-rw-r--r-- | server/src/vm/library.lua | 112 | ||||
-rw-r--r-- | server/src/vm/list.lua | 30 | ||||
-rw-r--r-- | server/src/vm/local.lua | 191 | ||||
-rw-r--r-- | server/src/vm/manager.lua | 17 | ||||
-rw-r--r-- | server/src/vm/module.lua | 56 | ||||
-rw-r--r-- | server/src/vm/multi.lua | 83 | ||||
-rw-r--r-- | server/src/vm/pcall.lua | 50 | ||||
-rw-r--r-- | server/src/vm/raw.lua | 30 | ||||
-rw-r--r-- | server/src/vm/source.lua | 183 | ||||
-rw-r--r-- | server/src/vm/special.lua | 130 | ||||
-rw-r--r-- | server/src/vm/value.lua | 634 | ||||
-rw-r--r-- | server/src/vm/vm.lua | 1334 |
19 files changed, 0 insertions, 3990 deletions
diff --git a/server/src/vm/chain.lua b/server/src/vm/chain.lua deleted file mode 100644 index 6e7c6ac7..00000000 --- a/server/src/vm/chain.lua +++ /dev/null @@ -1,65 +0,0 @@ -local valueMgr = require 'vm.value' -local sourceMgr = require 'vm.source' - -local mt = {} -mt.__index = mt -mt.type = 'chain' - -mt.min = 100 -mt.max = 100 -mt.count = 0 - -function mt:clearCache() - if self.count <= self.max then - return - end - local clock = os.clock() - local n = 0 - for uri, value in pairs(self.cache) do - local ok = value:eachInfo(function () - return true - end) - if ok then - n = n + 1 - else - value:getSource():kill() - self.cache[uri] = nil - end - end - self.count = n - self.max = self.count * 1.1 + 10 - if self.max < self.min then - self.max = self.min - end - local passed = os.clock() - clock - if passed > 0.1 then - log.warn(('chain:clearCache takes: [%.3f]sec, self.count: %d'):format(passed, self.count)) - end -end - -function mt:get(uri) - if not self.cache[uri] then - self.count = self.count + 1 - self:clearCache() - self.cache[uri] = valueMgr.create('any', sourceMgr.dummy()) - self.cache[uri]:markGlobal() - self.cache[uri].uri = uri - end - return self.cache[uri] -end - -function mt:remove() - if self.removed then - return - end - self.removed = true - for _, value in pairs(self.cache) do - value:getSource():kill() - end -end - -return function () - return setmetatable({ - cache = {}, - }, mt) -end diff --git a/server/src/vm/emmy.lua b/server/src/vm/emmy.lua deleted file mode 100644 index 9342a851..00000000 --- a/server/src/vm/emmy.lua +++ /dev/null @@ -1,372 +0,0 @@ -local functionMgr = require 'vm.function' -local library = require 'vm.library' -local mt = require 'vm.manager' - -function mt:clearEmmy() - self._emmy = nil - self._emmyParams = nil - self._emmyReturns = nil - self._emmyGeneric = nil - self._emmyComment = nil - self._emmyOverLoads = nil -end - -function mt:doEmmy(action) - local tp = action.type - if tp == 'emmyClass' then - self:doEmmyClass(action) - elseif tp == 'emmyType' then - self:doEmmyType(action) - elseif tp == 'emmyAlias' then - self:doEmmyAlias(action) - elseif tp == 'emmyParam' then - self:doEmmyParam(action) - elseif tp == 'emmyReturn' then - self:doEmmyReturn(action) - elseif tp == 'emmyField' then - self:doEmmyField(action) - elseif tp == 'emmyGeneric' then - self:doEmmyGeneric(action) - elseif tp == 'emmyVararg' then - self:doEmmyVararg(action) - elseif tp == 'emmyLanguage' then - elseif tp == 'emmyArrayType' then - self:doEmmyArrayType(action) - elseif tp == 'emmyTableType' then - self:doEmmyTableType(action) - elseif tp == 'emmyFunctionType' then - self:doEmmyFunctionType(action) - elseif tp == 'emmySee' then - self:doEmmySee(action) - elseif tp == 'emmyOverLoad' then - self:doEmmyOverLoad(action) - elseif tp == 'emmyIncomplete' then - self:doEmmyIncomplete(action) - elseif tp == 'emmyComment' then - self:doEmmyComment(action) - end -end - -function mt:getEmmy() - local emmy = self._emmy - self._emmy = nil - return emmy -end - -function mt:addEmmyParam(param) - if not self._emmyParams then - self._emmyParams = {} - end - self._emmyParams[#self._emmyParams+1] = param -end - -function mt:addEmmyReturn(rtn) - if not self._emmyReturns then - self._emmyReturns = {} - end - self._emmyReturns[#self._emmyReturns+1] = rtn -end - -function mt:addEmmyOverLoad(funcObj) - if not self._emmyOverLoads then - self._emmyOverLoads = {} - end - self._emmyOverLoads[#self._emmyOverLoads+1] = funcObj -end - -function mt:getEmmyParams() - local params = self._emmyParams - self._emmyParams = nil - return params -end - -function mt:getEmmyReturns() - local returns = self._emmyReturns - self._emmyReturns = nil - return returns -end - -function mt:getEmmyOverLoads() - local overLoads = self._emmyOverLoads - self._emmyOverLoads = nil - return overLoads -end - -function mt:getEmmyGeneric() - local generic = self._emmyGeneric - self._emmyGeneric = nil - return generic -end - ----@return string -function mt:getEmmyComment() - local comment = self._emmyComment - self._emmyComment = nil - return comment -end - -function mt:doEmmyClass(action) - ---@type emmyMgr - local emmyMgr = self.emmyMgr - self:instantSource(action) - self:instantSource(action[1]) - local class = emmyMgr:addClass(action) - action:set('emmy class', class:getName()) - action[1]:set('emmy class', class:getName()) - local extends = action[2] - if extends then - self:instantSource(extends) - extends:set('emmy class', extends[1]) - end - self._emmy = class - action:set('emmy.class', class) - if self.lsp then - self.lsp.global:markSet(self:getUri()) - end -end - -function mt:buildEmmyType(action) - ---@type emmyMgr - local emmyMgr = self.emmyMgr - self:instantSource(action) - for _, obj in ipairs(action) do - self:instantSource(obj) - obj:set('emmy class', obj[1]) - end - local type = emmyMgr:addType(action) - return type -end - -function mt:doEmmyType(action) - local type = self:buildEmmyType(action) - self._emmy = type - if self.lsp then - self.lsp.global:markGet(self:getUri()) - end - return type -end - -function mt:doEmmyAlias(action) - ---@type emmyMgr - local emmyMgr = self.emmyMgr - self:instantSource(action) - self:instantSource(action[1]) - local type = self:buildEmmyAnyType(action[2]) - local alias = emmyMgr:addAlias(action, type) - action:set('emmy.alias', alias) - action[1]:set('emmy class', alias:getName()) - self._emmy = type - if self.lsp then - self.lsp.global:markSet(self:getUri()) - end -end - -function mt:getGenericByType(type) - local generics = self._emmyGeneric - if not generics then - return - end - if #type > 1 then - return - end - local name = type[1][1] - for _, generic in ipairs(generics) do - if generic:getName() == name then - return generic - end - end - return nil -end - -function mt:doEmmyParam(action) - ---@type emmyMgr - local emmyMgr = self.emmyMgr - self:instantSource(action) - self:instantSource(action[1]) - local type = self:getGenericByType(action[2]) or self:buildEmmyAnyType(action[2]) - local param = emmyMgr:addParam(action, type) - action:set('emmy.param', param) - self:addEmmyParam(param) - if self.lsp then - self.lsp.global:markGet(self:getUri()) - end -end - -function mt:doEmmyReturn(action) - ---@type emmyMgr - local emmyMgr = self.emmyMgr - self:instantSource(action) - local type = action[1] and (self:getGenericByType(action[1]) or self:buildEmmyAnyType(action[1])) - local name = action[2] - local rtn = emmyMgr:addReturn(action, type, name) - action:set('emmy.return', rtn) - self:addEmmyReturn(rtn) - if self.lsp then - self.lsp.global:markGet(self:getUri()) - end -end - -function mt:doEmmyField(action) - ---@type emmyMgr - local emmyMgr = self.emmyMgr - self:instantSource(action) - self:instantSource(action[2]) - local type = self:buildEmmyAnyType(action[3]) - local value = self:createValue('nil', action[2]) - local field = emmyMgr:addField(action, type, value) - value:setEmmy(type) - action:set('emmy.field', field) - - local class = self._emmy - if not self._emmy or self._emmy.type ~= 'emmy.class' then - return - end - class:addField(field) - action:set('target class', class) -end - -function mt:doEmmyGeneric(action) - ---@type emmyMgr - local emmyMgr = self.emmyMgr - self:instantSource(action) - - local defs = {} - for i, obj in ipairs(action) do - defs[i] = {} - defs[i].name = self:instantSource(obj[1]) - if obj[2] then - defs[i].type = self:buildEmmyAnyType(obj[2]) - end - end - - local generic = emmyMgr:addGeneric(defs) - self._emmyGeneric = generic -end - -function mt:doEmmyVararg(action) - ---@type emmyMgr - local emmyMgr = self.emmyMgr - self:instantSource(action) - local type = self:getGenericByType(action[1]) or self:buildEmmyAnyType(action[1]) - local param = emmyMgr:addParam(action, type) - action:set('emmy.param', param) - self:addEmmyParam(param) - if self.lsp then - self.lsp.global:markGet(self:getUri()) - end -end - -function mt:buildEmmyArrayType(action) - ---@type emmyMgr - local emmyMgr = self.emmyMgr - self:instantSource(action) - for _, obj in ipairs(action) do - self:instantSource(obj) - action:set('emmy class', obj[1]) - end - local type = emmyMgr:addArrayType(action) - return type -end - -function mt:doEmmyArrayType(action) - local type = self:buildEmmyArrayType(action) - self._emmy = type - if self.lsp then - self.lsp.global:markGet(self:getUri()) - end - return type -end - -function mt:buildEmmyTableType(action) - ---@type emmyMgr - local emmyMgr = self.emmyMgr - self:instantSource(action) - local keyType = self:buildEmmyAnyType(action[1]) - local valueType = self:buildEmmyAnyType(action[2]) - local type = emmyMgr:addTableType(action, keyType, valueType) - return type -end - -function mt:doEmmyTableType(action) - local type = self:buildEmmyTableType(action) - self._emmy = type - if self.lsp then - self.lsp.global:markGet(self:getUri()) - end - return type -end - -function mt:buildEmmyFunctionType(source) - ---@type emmyMgr - local emmyMgr = self.emmyMgr - self:instantSource(source) - local funcObj = emmyMgr:addFunctionType(source) - ---@type emmyFunction - local func = functionMgr.create(source) - local args = source.args - if args then - for i = 1, #args // 2 do - local nameSource = args[i*2-1] - local typeSource = args[i*2] - local paramType = self:buildEmmyAnyType(typeSource) - funcObj:addParam(nameSource[1], paramType) - local value = self:createValue(paramType:getType(), typeSource) - value:setEmmy(paramType) - self:instantSource(nameSource) - local arg = func:addArg(nameSource[1], nameSource, value) - arg:set('emmy arg', true) - end - end - local returns = source.returns - if returns then - for i = 1, #returns do - local returnSource = returns[i] - local returnType = self:buildEmmyAnyType(returnSource) - funcObj:addReturn(returnType) - local value = self:createValue(returnType:getType(), returnSource) - value:setEmmy(returnType) - func:setReturn(i, value) - end - end - funcObj:bindFunction(func) - return funcObj -end - -function mt:doEmmyFunctionType(action) - local funcObj = self:buildEmmyFunctionType(action) - self._emmy = funcObj - return funcObj -end - -function mt:buildEmmyAnyType(source) - if source.type == 'emmyType' then - return self:buildEmmyType(source) - elseif source.type == 'emmyArrayType' then - return self:buildEmmyArrayType(source) - elseif source.type == 'emmyTableType' then - return self:buildEmmyTableType(source) - elseif source.type == 'emmyFunctionType' then - return self:buildEmmyFunctionType(source) - else - error('Unknown emmy type: ' .. table.dump(source)) - end -end - -function mt:doEmmyIncomplete(action) - self:instantSource(action) -end - -function mt:doEmmyComment(action) - self._emmyComment = action[1] -end - -function mt:doEmmySee(action) - self:instantSource(action) - self:instantSource(action[2]) - action[2]:set('emmy see', action) -end - -function mt:doEmmyOverLoad(action) - local funcObj = self:buildEmmyFunctionType(action) - self:addEmmyOverLoad(funcObj) -end diff --git a/server/src/vm/function.lua b/server/src/vm/function.lua deleted file mode 100644 index 1ba01363..00000000 --- a/server/src/vm/function.lua +++ /dev/null @@ -1,551 +0,0 @@ -local createMulti = require 'vm.multi' -local valueMgr = require 'vm.value' -local localMgr = require 'vm.local' -local sourceMgr = require 'vm.source' -local listMgr = require 'vm.list' - -local Watch = setmetatable({}, {__mode = 'kv'}) - ----@class emmyFunction -local mt = {} -mt.__index = mt -mt.type = 'function' -mt._runed = 0 -mt._top = 0 - -function mt:getSource() - return listMgr.get(self.source) -end - -function mt:getUri() - local source = self:getSource() - return source and source.uri or '' -end - -function mt:push(source, ischunk) - if self._removed then - return - end - self._top = self._top + 1 - self.locals[self._top] = {} - 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 - end - 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 - self._top = self._top - 1 -end - -function mt:saveLocal(name, loc) - if self._removed then - return - end - if loc.type ~= 'local' then - error('saveLocal必须是local') - end - if not loc:getSource() then - return - end - local old = self:loadLocal(name) - if old then - loc:shadow(old) - end - 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] - local loc = locals[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 - -function mt:eachLocal(callback) - local mark = {} - for i = self._top, 1, -1 do - local locals = self.locals[i] - for name, loc in pairs(locals) do - if not mark[name] then - mark[name] = true - local res = callback(name, loc) - if res ~= nil then - return res - 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 - -function mt:saveLabel(label) - if self._removed then - return - end - if not self._label then - self._label = {} - end - self._label[#self._label+1] = label -end - -function mt:loadLabel(name) - if not self._label then - return nil - end - for _, label in ipairs(self._label) do - if label:getName() == name then - return label - end - end - return nil -end - -function mt:rawSetReturn(index, value) - if self._removed then - return - end - self:set('hasReturn', true) - if not self.returns then - self.returns = createMulti() - end - if value then - self.returns:set(index, value) - if self._global then - value:markGlobal() - end - end -end - -function mt:setReturn(index, value) - local emmy = self._emmyReturns and self._emmyReturns[index] - if emmy then - if emmy:bindType() or emmy:bindGeneric() then - return - end - end - return self:rawSetReturn(index, value) -end - -function mt:mergeReturn(index, value) - if self._removed then - return - end - local emmy = self._emmyReturns and self._emmyReturns[index] - if emmy then - if emmy:bindType() or emmy:bindGeneric() then - return - end - end - self:set('hasReturn', true) - if not self.returns then - self.returns = createMulti() - end - if value then - if self.returns[index] then - self.returns[index]:mergeValue(value) - self.returns[index] = value - else - self.returns:set(index, value) - end - end - if self._global then - value:markGlobal() - end -end - -function mt:getReturn(index) - if self._removed then - return nil - end - if self.maxReturns and index and self.maxReturns < index then - return nil - end - if not self.returns then - self.returns = createMulti() - end - if index then - return self.returns:get(index) - else - return self.returns - end -end - -function mt:returnDots(index) - if not self.returns then - self.returns = createMulti() - end - --self.returns[index] = createMulti() -end - -function mt:loadDots() - if not self._dots then - self._dots = createMulti() - end - self._dotsLoad = true - return self._dots -end - -function mt:setObject(value, source) - self._objectValue = value - self._objectSource = source -end - -function mt:getObject() - return self._objectSource, self._objectValue -end - -function mt:hasRuned() - return self._runed > 0 -end - -function mt:needSkip() - return self._runed > 3 -end - ----@param vm VM -function mt:run(vm) - if self._removed then - return - end - if not self:getSource() then - return - end - - self._runed = self._runed + 1 - - -- 第一次运行函数时,创建函数的参数 - if self._runed == 1 then - -- 如果是面向对象形式的函数,创建隐藏的参数self - if self._objectSource then - local loc = localMgr.create('self', vm:instantSource(self._objectSource), self._objectValue) - loc:set('hide', true) - loc:set('start', self:getSource().start) - loc:close(self:getSource().finish) - self:saveUpvalue('self', loc) - self.args[#self.args+1] = loc - end - - -- 显性声明的参数 - self:createArgs(vm) - end - - if self:needSkip() then - return - end - - -- 向局部变量中填充参数 - for i, loc in ipairs(self.args) do - loc:setValue(self.argValues[i]) - local emmyParam = self:findEmmyParamByName(loc:getName()) - if emmyParam then - local typeObj = emmyParam:bindType() - if typeObj then - loc:getValue():setEmmy(typeObj) - end - local genericObj = emmyParam:bindGeneric() - if genericObj then - genericObj:setValue(loc:getValue()) - end - end - end - if self._dots then - local emmyParam = self:findEmmyParamByName('...') - self._dots = createMulti() - for i = #self.args + 1, #self.argValues do - local value = self.argValues[i] - self._dots:push(value) - if emmyParam then - local typeObj = emmyParam:bindType() - if typeObj then - value:setEmmy(typeObj) - end - local genericObj = emmyParam:bindGeneric() - if genericObj then - genericObj:setValue(value) - end - end - end - if emmyParam then - local typeObj = emmyParam:bindType() - if typeObj then - self._dots:setEmmy(typeObj) - end - local genericObj = emmyParam:bindGeneric() - if genericObj then - local value = self._dots:first() - if value then - genericObj:setValue(value) - end - end - end - end - - -- 填充返回值 - if self._emmyReturns then - for i, rtn in ipairs(self._emmyReturns) do - local value = vm:createValue('nil', rtn:getSource()) - local typeObj = rtn:bindType() - if typeObj then - value:setEmmy(typeObj) - end - local genericObj = rtn:bindGeneric() - if genericObj then - local destValue = genericObj:getValue() - if destValue then - value:mergeType(destValue) - end - end - self:rawSetReturn(i, value) - end - end -end - -function mt:eachEmmyReturn(callback) - if not self._emmyReturns then - return - end - for _, rtn in ipairs(self._emmyReturns) do - callback(rtn) - end -end - -function mt:setArgs(values) - for i = 1, #self.argValues do - self.argValues[i] = nil - end - for i = 1, #values do - self.argValues[i] = values[i] - end -end - -function mt:findEmmyParamByName(name) - local params = self._emmyParams - if not params then - return nil - end - for i = #params, 1, -1 do - local param = params[i] - if param:getName() == name then - return param - end - end - return nil -end - -function mt:findEmmyParamByIndex(index) - local arg = self.args[index] - if not arg then - return nil - end - local name = arg:getName() - return self:findEmmyParamByName(name) -end - -function mt:addArg(name, source, value, close) - local loc = localMgr.create(name, source, value) - loc:close(close) - self:saveUpvalue(name, loc) - self.args[#self.args+1] = loc - return loc -end - -function mt:createArg(vm, arg, close) - vm:instantSource(arg) - arg:set('arg', self) - if arg.type == 'name' then - vm:instantSource(arg) - local value = valueMgr.create('nil', arg) - self:addArg(arg[1], arg, value, close) - elseif arg.type == '...' then - self._dots = createMulti() - self._dotsSource = arg - end -end - -function mt:createLibArg(arg, source) - if arg.type == '...' then - self._dots = createMulti() - else - local name = arg.name or '_' - local loc = localMgr.create(name, source, valueMgr.create('any', source)) - self:saveUpvalue(name, loc) - self.args[#self.args+1] = loc - end -end - -function mt:hasDots() - return self._dots ~= nil -end - -function mt:createArgs(vm) - if not self:getSource() then - return - end - local args = self:getSource().arg - if not args then - return - end - local close = self:getSource().finish - if args.type == 'list' then - for _, arg in ipairs(args) do - self:createArg(vm, arg, close) - end - else - self:createArg(vm, args, close) - end -end - -function mt:set(name, v) - if not self._flag then - self._flag = {} - end - self._flag[name] = v -end - -function mt:get(name) - if not self._flag then - return nil - end - return self._flag[name] -end - -function mt:getSource() - if self._removed then - return nil - end - return listMgr.get(self.source) -end - -function mt:kill() - if self._removed then - return - end - self._removed = true - listMgr.clear(self.id) -end - -function mt:markGlobal() - if self._global then - return - end - self._global = true - if self.returns then - self.returns:eachValue(function (_, v) - v:markGlobal() - end) - end -end - -function mt:setEmmy(params, returns, overLoads) - if params then - self._emmyParams = params - for _, param in ipairs(params) do - param:getSource():set('emmy function', self) - param:getSource()[1]:set('emmy function', self) - end - end - if returns then - self._emmyReturns = returns - for _, rtn in ipairs(returns) do - rtn:getSource():set('emmy function', self) - end - end - if overLoads then - self._emmyOverLoads = overLoads - for _, ol in ipairs(overLoads) do - ol:getSource():set('emmy function', self) - end - end -end - ----@param comment string -function mt:setComment(comment) - self._comment = comment -end - ----@return string -function mt:getComment() - return self._comment -end - -function mt:getEmmyParams() - return self._emmyParams -end - -function mt:getEmmyOverLoads() - return self._emmyOverLoads -end - -local function create(source) - if not source then - error('Function need source') - end - local id = source.id - if not id then - error('Not instanted source') - end - local self = setmetatable({ - source = id, - locals = {}, - upvalues = {}, - chunk = {}, - finishs = {}, - args = {}, - argValues = {}, - }, mt) - - local id = listMgr.add(self) - self.id = id - Watch[self] = id - return self -end - -return { - create = create, - watch = Watch, -} diff --git a/server/src/vm/global.lua b/server/src/vm/global.lua deleted file mode 100644 index af30ffdd..00000000 --- a/server/src/vm/global.lua +++ /dev/null @@ -1,25 +0,0 @@ -local library = require 'core.library' -local libraryBuilder = require 'vm.library' -local sourceMgr = require 'vm.source' - -return function (lsp) - local global = lsp and lsp.globalValue - if not global then - libraryBuilder.clear() - local t = {} - for name, lib in pairs(library.global) do - t[name] = libraryBuilder.value(lib) - end - - global = t._G - global:markGlobal() - global:set('ENV', true) - for k, v in pairs(t) do - global:setChild(k, v, sourceMgr.dummy()) - end - end - if lsp then - lsp.globalValue = global - end - return global -end diff --git a/server/src/vm/init.lua b/server/src/vm/init.lua deleted file mode 100644 index 87576ba5..00000000 --- a/server/src/vm/init.lua +++ /dev/null @@ -1 +0,0 @@ -return require 'vm.vm' diff --git a/server/src/vm/ipairs.lua b/server/src/vm/ipairs.lua deleted file mode 100644 index cb8356da..00000000 --- a/server/src/vm/ipairs.lua +++ /dev/null @@ -1,51 +0,0 @@ -local mt = require 'vm.manager' -local library = require 'vm.library' - ----@param func emmyFunction -function mt:callIpairs(func, values, source) - local tbl = values[1] - func:setReturn(1, library.special['@ipairs']) - func:setReturn(2, tbl) -end - ----@param func emmyFunction -function mt:callAtIpairs(func, values, source) - local tbl = values[1] - if tbl then - local emmy = tbl:getEmmy() - if emmy then - if emmy.type == 'emmy.arrayType' then - local value = self:createValue(emmy:getName(), source) - func:setReturn(2, value) - end - end - end -end - ----@param func emmyFunction -function mt:callPairs(func, values, source) - local tbl = values[1] - func:setReturn(1, library.special['next']) - func:setReturn(2, tbl) -end - ----@param func emmyFunction -function mt:callNext(func, values, source) - local tbl = values[1] - if tbl then - local emmy = tbl:getEmmy() - if emmy then - if emmy.type == 'emmy.arrayType' then - local key = self:createValue('integer', source) - local value = self:createValue(emmy:getName(), source) - func:setReturn(1, key) - func:setReturn(2, value) - elseif emmy.type == 'emmy.tableType' then - local key = self:createValue(emmy:getKeyType():getType(), source) - local value = self:createValue(emmy:getValueType():getType(), source) - func:setReturn(1, key) - func:setReturn(2, value) - end - end - end -end diff --git a/server/src/vm/label.lua b/server/src/vm/label.lua deleted file mode 100644 index c0e0dfb8..00000000 --- a/server/src/vm/label.lua +++ /dev/null @@ -1,75 +0,0 @@ -local listMgr = require 'vm.list' - -local Sort = 0 - -local mt = {} -mt.__index = mt -mt.type = 'label' - -function mt:getName() - return self.name -end - -function mt:addInfo(tp, source) - if not source then - error('No source') - end - local id = source.id - if not id then - error('Not instanted source') - end - if self._info[id] then - return - end - Sort = Sort + 1 - local info = { - type = tp, - source = id, - _sort = Sort, - } - - self._info[id] = info -end - -function mt:eachInfo(callback) - local list = {} - for srcId, info in pairs(self._info) do - local src = listMgr.get(srcId) - if src then - list[#list+1] = info - else - self._info[srcId] = nil - end - end - table.sort(list, function (a, b) - return a._sort < b._sort - end) - for i = 1, #list do - local info = list[i] - local res = callback(info, listMgr.get(info.source)) - if res ~= nil then - return res - end - end - return nil -end - -function mt:getSource() - return listMgr.get(self.source) -end - -return function (name, source) - if not source then - error('No source') - end - local id = source.id - if not id then - error('Not instanted source') - end - local self = setmetatable({ - name = name, - source = id, - _info = {}, - }, mt) - return self -end diff --git a/server/src/vm/library.lua b/server/src/vm/library.lua deleted file mode 100644 index 018d69f3..00000000 --- a/server/src/vm/library.lua +++ /dev/null @@ -1,112 +0,0 @@ -local sourceMgr = require 'vm.source' - -local valueMgr -local functionMgr - -local CHILD_CACHE = {} -local VALUE_CACHE = {} -local Special = {} - -local buildLibValue -local buildLibChild - -function buildLibValue(lib) - if VALUE_CACHE[lib] then - return VALUE_CACHE[lib] - end - if not valueMgr then - valueMgr = require 'vm.value' - functionMgr = require 'vm.function' - end - local tp = lib.type - local value - if tp == 'table' then - value = valueMgr.create('table', sourceMgr.dummy()) - elseif tp == 'function' then - local dummySource = sourceMgr.dummy() - value = valueMgr.create('function', dummySource) - local func = functionMgr.create(dummySource) - value:setFunction(func) - if lib.args then - for _, arg in ipairs(lib.args) do - func:createLibArg(arg, sourceMgr.dummy()) - end - end - if lib.returns then - for i, rtn in ipairs(lib.returns) do - if rtn.type == '...' then - func:returnDots(i) - else - func:setReturn(i, buildLibValue(rtn)) - end - end - if lib.special == 'pairs' then - func:setReturn(1, Special['next']) - end - if lib.special == 'ipairs' then - func:setReturn(1, Special['@ipairs']) - end - end - elseif tp == 'string' then - value = valueMgr.create('string', sourceMgr.dummy()) - elseif tp == 'boolean' then - value = valueMgr.create('boolean', sourceMgr.dummy()) - elseif tp == 'number' then - value = valueMgr.create('number', sourceMgr.dummy()) - elseif tp == 'integer' then - value = valueMgr.create('integer', sourceMgr.dummy()) - elseif tp == 'nil' then - value = valueMgr.create('nil', sourceMgr.dummy()) - else - value = valueMgr.create(tp or 'any', sourceMgr.dummy()) - end - value:setLib(lib) - VALUE_CACHE[lib] = value - - if lib.child then - for fName, fLib in pairs(lib.child) do - local fValue = buildLibValue(fLib) - value:rawSet(fName, fValue) - value:addInfo('set child', sourceMgr.dummy(), fName, fValue) - end - end - - if lib.special == 'next' then - Special['next'] = value - end - if lib.special == '@ipairs' then - Special['@ipairs'] = value - return nil - end - - return value -end - -function buildLibChild(lib) - if not valueMgr then - valueMgr = require 'vm.value' - functionMgr = require 'vm.function' - end - if CHILD_CACHE[lib] then - return CHILD_CACHE[lib] - end - local child = {} - for fName, fLib in pairs(lib.child) do - local fValue = buildLibValue(fLib) - child[fName] = fValue - end - CHILD_CACHE[lib] = child - return child -end - -local function clearCache() - CHILD_CACHE = {} - VALUE_CACHE = {} -end - -return { - value = buildLibValue, - child = buildLibChild, - clear = clearCache, - special = Special, -} diff --git a/server/src/vm/list.lua b/server/src/vm/list.lua deleted file mode 100644 index 234f241f..00000000 --- a/server/src/vm/list.lua +++ /dev/null @@ -1,30 +0,0 @@ -local Id = 0 -local Version = 0 -local List = {} - -local function get(id) - return List[id] -end - -local function add(obj) - Id = Id + 1 - List[Id] = obj - return Id -end - -local function clear(id) - List[id] = nil - Version = Version + 1 -end - -local function getVersion() - return Version -end - -return { - get = get, - add = add, - clear = clear, - list = List, - getVersion = getVersion, -} diff --git a/server/src/vm/local.lua b/server/src/vm/local.lua deleted file mode 100644 index 7e8af0f1..00000000 --- a/server/src/vm/local.lua +++ /dev/null @@ -1,191 +0,0 @@ -local listMgr = require 'vm.list' - -local Sort = 0 -local Watch = setmetatable({}, {__mode = 'kv'}) - ----@class Local -local mt = {} -mt.__index = mt -mt.type = 'local' -mt._close = math.maxinteger - -function mt:setValue(value) - if not value then - return - end - if self.value then - --self.value:mergeValue(value) - self.value:mergeType(value) - self.value = value - else - self.value = value - end - if self._emmy then - self.value:setEmmy(self._emmy) - end - return value -end - -function mt:getValue() - return self.value -end - -function mt:addInfo(tp, source) - if not source then - error('No source') - end - local id = source.id - if not id then - error('Not instanted source') - end - if self._info[id] then - return - end - Sort = Sort + 1 - local info = { - type = tp, - source = id, - _sort = Sort, - } - - self._info[id] = info -end - -function mt:eachInfo(callback) - local list = {} - for srcId, info in pairs(self._info) do - local src = listMgr.get(srcId) - if src then - list[#list+1] = info - else - self._info[srcId] = nil - end - end - table.sort(list, function (a, b) - return a._sort < b._sort - end) - for i = 1, #list do - local info = list[i] - local res = callback(info, listMgr.get(info.source)) - if res ~= nil then - return res - end - end - return nil -end - -function mt:set(name, v) - if not self._flag then - self._flag = {} - end - self._flag[name] = v -end - -function mt:get(name) - if not self._flag then - return nil - end - return self._flag[name] -end - -function mt:getName() - return self.name -end - -function mt:shadow(old) - if not old then - if not self._shadow then - return nil - end - for i = #self._shadow, 1, -1 do - local loc = self._shadow[i] - if not loc:getSource() then - table.remove(self._shadow, i) - end - end - return self._shadow - end - local group = old._shadow - if not group then - group = {} - group[#group+1] = old - end - group[#group+1] = self - self._shadow = group - - if not self:getSource() then - log.error('local no source') - return - end - - old:close(self:getSource().start - 1) -end - -function mt:close(pos) - if pos then - if pos <= 0 then - pos = math.maxinteger - end - self._close = pos - else - return self._close - end -end - -function mt:getSource() - return listMgr.get(self.source) -end - -local EMMY_TYPE = { - ['emmy.class'] = true, - ['emmy.type'] = true, - ['emmy.arrayType'] = true, - ['emmy.tableType'] = true, - ['emmy.functionType'] = true, -} - -function mt:setEmmy(emmy) - if not emmy then - return - end - if self.value and EMMY_TYPE[emmy.type] then - self.value:setEmmy(emmy) - end -end - ----@param comment string -function mt:setComment(comment) - self._comment = comment -end - ----@return string -function mt:getComment() - return self._comment -end - -local function create(name, source, value, tags) - if not value then - error('Local must has a value') - end - if not source then - error('No source') - end - local id = source.id - if not id then - error('Not instanted source') - end - local self = setmetatable({ - name = name, - source = id, - value = value, - tags = tags, - _info = {}, - }, mt) - Watch[self] = true - return self -end - -return { - create = create, - watch = Watch, -} diff --git a/server/src/vm/manager.lua b/server/src/vm/manager.lua deleted file mode 100644 index b9762d2e..00000000 --- a/server/src/vm/manager.lua +++ /dev/null @@ -1,17 +0,0 @@ ----@class VM -local mt = {} -mt.__index = mt -mt.type = 'vm' -mt._version = -1 - ----@param version integer -function mt:setVersion(version) - self._version = version -end - ----@return integer -function mt:getVersion() - return self._version -end - -return mt diff --git a/server/src/vm/module.lua b/server/src/vm/module.lua deleted file mode 100644 index 60191bf3..00000000 --- a/server/src/vm/module.lua +++ /dev/null @@ -1,56 +0,0 @@ -local mt = require 'vm.manager' -local createMulti = require 'vm.multi' - ---[[ -function module(name, ...) - local env = {} - for _, opt in ipairs {...} do - opt(env) - end - @ENV = env -end ---]] -function mt:callModuel(func, values) - local envLoc = self:loadLocal('@ENV') - if not envLoc then - return - end - local source = self:getDefaultSource() - local newEnvValue = self:createValue('table', source) - local args = createMulti() - - args:push(newEnvValue) - - for i = 2, #values do - local value = values[i] - -- opt(env) - self:call(value, args, source) - end - - -- @ENV = env - envLoc:setValue(newEnvValue) -end - ---[[ -function package.seeall(env) - setmetatable(env, { __index = @ENV }) -end ---]] -function mt:callSeeAll(func, values) - local newEnv = values[1] - if not newEnv then - return - end - local envLoc = self:loadLocal('@ENV') - if not envLoc then - return - end - local oldEnv = envLoc:getValue() - if not oldEnv then - return - end - local source = self:getDefaultSource() - local meta = self:createValue('table', source) - meta:setChild('__index', oldEnv, source) - newEnv:setMetaTable(meta) -end diff --git a/server/src/vm/multi.lua b/server/src/vm/multi.lua deleted file mode 100644 index 4b27b8cf..00000000 --- a/server/src/vm/multi.lua +++ /dev/null @@ -1,83 +0,0 @@ -local mt = {} -mt.__index = mt -mt.type = 'multi' -mt.len = 0 - -function mt:push(value, isLast) - if value and value.type == 'list' then - if isLast then - for _, v in ipairs(value) do - self.len = self.len + 1 - self[self.len] = v - end - else - self.len = self.len + 1 - self[self.len] = value[1] - end - else - self.len = self.len + 1 - self[self.len] = value - end -end - -function mt:get(index) - return self[index] -end - -function mt:set(index, value) - if index > self.len then - self.len = index - end - self[index] = value -end - -function mt:first() - local value = self[1] - if not value then - return nil - end - if value.type == 'multi' then - return value:first() - else - return value - end -end - -function mt:eachValue(callback) - local i = 0 - for n, value in ipairs(self) do - if value.type == 'multi' then - if n == self.len then - value:eachValue(function (_, nvalue) - i = i + 1 - callback(i, nvalue) - end) - else - i = i + 1 - value:first() - end - else - i = i + 1 - callback(i, value) - end - end -end - -function mt:merge(other) - other:eachValue(function (_, value) - self:push(value) - end) -end - -function mt:setEmmy(emmy) - self._emmy = emmy -end - -function mt:getEmmy() - return self._emmy -end - -return function () - local self = setmetatable({}, mt) - return self -end diff --git a/server/src/vm/pcall.lua b/server/src/vm/pcall.lua deleted file mode 100644 index e5d1e26f..00000000 --- a/server/src/vm/pcall.lua +++ /dev/null @@ -1,50 +0,0 @@ -local mt = require 'vm.manager' -local multi = require 'vm.multi' - -function mt:callPcall(func, values, source) - local funcValue = values:first() - if not funcValue then - return - end - local realFunc = funcValue:getFunction() - if not realFunc then - return - end - local argList = multi() - values:eachValue(function (i, v) - if i >= 2 then - argList:push(v) - end - end) - self:call(funcValue, argList, source) - if realFunc ~= func then - func:setReturn(1, self:createValue('boolean', source)) - realFunc:getReturn():eachValue(function (i, v) - func:setReturn(i + 1, v) - end) - end -end - -function mt:callXpcall(func, values, source) - local funcValue = values:first() - if not funcValue then - return - end - local realFunc = funcValue:getFunction() - if not realFunc then - return - end - local argList = multi() - values:eachValue(function (i, v) - if i >= 3 then - argList:push(v) - end - end) - self:call(funcValue, argList, source) - if realFunc ~= func then - func:setReturn(1, self:createValue('boolean', source)) - realFunc:getReturn():eachValue(function (i, v) - func:setReturn(i + 1, v) - end) - end -end diff --git a/server/src/vm/raw.lua b/server/src/vm/raw.lua deleted file mode 100644 index f8c35734..00000000 --- a/server/src/vm/raw.lua +++ /dev/null @@ -1,30 +0,0 @@ -local mt = require 'vm.manager' - -function mt:callRawSet(func, values, source) - local tbl = values[1] - local index = values[2] - local value = values[3] - if not tbl or not index or not value then - return - end - if index:getLiteral() then - index = index:getLiteral() - end - tbl:addInfo('set child', source, index) - tbl:rawSet(index, value, source) - func:setReturn(1, tbl) -end - -function mt:callRawGet(func, values, source) - local tbl = values[1] - local index = values[2] - if not tbl or not index then - return - end - if index:getLiteral() then - index = index:getLiteral() - end - tbl:addInfo('get child', source, index) - local value = tbl:rawGet(index) - func:setReturn(1, value) -end diff --git a/server/src/vm/source.lua b/server/src/vm/source.lua deleted file mode 100644 index 7a10a38e..00000000 --- a/server/src/vm/source.lua +++ /dev/null @@ -1,183 +0,0 @@ -local listMgr = require 'vm.list' - ----@class source -local mt = {} -mt.__index = mt -mt.type = 'source' -mt.uri = '' -mt.start = 0 -mt.finish = 0 -mt.id = 0 - -local Watch = setmetatable({}, {__mode = 'k'}) - -function mt:bindLocal(loc, action) - if loc then - self._bindLocal = loc - self._bindValue = loc:getValue() - self._action = action - loc:addInfo(action, self) - else - if not self._bindLocal then - return nil - end - if not self._bindLocal:getSource() then - self._bindLocal = nil - return nil - end - return self._bindLocal - end -end - -function mt:bindLabel(label, action) - if label then - self._bindLabel = label - self._action = action - label:addInfo(action, self) - else - return self._bindLabel - end -end - -function mt:bindFunction(func) - if func then - self._bindFunction = func - else - return self._bindFunction - end -end - -function mt:bindValue(value, action) - if value then - self._bindValue = value - self._action = action - value:addInfo(action, self) - else - return self._bindValue - end -end - -function mt:bindCall(args) - if args then - self._bindCallArgs = args - else - return self._bindCallArgs - end -end - -function mt:bindMetatable(meta) - if meta then - self._bindMetatable = meta - else - return self._bindMetatable - end -end - -function mt:action() - return self._action -end - -function mt:setUri(uri) - self.uri = uri -end - -function mt:getUri() - return self.uri -end - -function mt:set(name, v) - if not self._flag then - self._flag = {} - end - self._flag[name] = v -end - -function mt:get(name) - if not self._flag then - return nil - end - return self._flag[name] -end - -function mt:getName() - return self[1] -end - -function mt:kill() - self._dead = true - listMgr.clear(self.id) -end - -function mt:isDead() - return self._dead -end - -function mt:findValue() - local value = self:bindValue() - if not value then - return nil - end - if not value:isGlobal() then - return value - end - if self.type ~= 'name' then - return value - end - local parent = self:get 'parent' - if not parent then - return value - end - local name = self[1] - if type(name) ~= 'string' then - return value - end - return parent:getChild(name) or value -end - -function mt:findCallFunction() - local simple = self:get 'simple' - if not simple then - return nil - end - local source - for i = 1, #simple do - if simple[i] == self then - source = simple[i-1] - end - end - if not source then - return nil - end - local value = source:bindValue() - if value and value:getFunction() then - return value - end - value = source:findValue() - if value and value:getFunction() then - return value - end - return nil -end - -local function instant(source) - if source.id then - return false - end - local id = listMgr.add(source) - source.id = id - Watch[source] = id - setmetatable(source, mt) - return true -end - -local function dummy() - local src = {} - instant(src) - return src -end - -return { - instant = instant, - watch = Watch, - dummy = dummy, -} diff --git a/server/src/vm/special.lua b/server/src/vm/special.lua deleted file mode 100644 index e93c4445..00000000 --- a/server/src/vm/special.lua +++ /dev/null @@ -1,130 +0,0 @@ -local mt = require 'vm.manager' -local multi = require 'vm.multi' -local library = require 'core.library' -local libraryBuilder = require 'vm.library' -local plugin = require 'plugin' - ----@param func emmyFunction ----@param values table -function mt:callEmmySpecial(func, values, source) - local emmyParams = func:getEmmyParams() - for index, param in ipairs(emmyParams) do - local option = param:getOption() - if option and type(option.special) == 'string' then - self:checkEmmyParam(func, values, index, option.special, source) - end - end -end - ----@param func emmyFunction ----@param values table ----@param index integer ----@param special string -function mt:checkEmmyParam(func, values, index, special, source) - if special == 'dofile:1' then - self:callEmmyDoFile(func, values, index) - elseif special == 'loadfile:1' then - self:callEmmyLoadFile(func, values, index) - elseif special == 'pcall:1' then - self:callEmmyPCall(func, values, index, source) - elseif special == 'require:1' then - self:callEmmyRequire(func, values, index) - end -end - ----@param func emmyFunction ----@param values table ----@param index integer -function mt:callEmmyDoFile(func, values, index) - if not values[index] then - values[index] = self:createValue('any', self:getDefaultSource()) - end - local str = values[index]:getLiteral() - if type(str) ~= 'string' then - return - end - local requireValue = self:tryRequireOne(str, values[index], 'dofile') - if not requireValue then - requireValue = self:createValue('any', self:getDefaultSource()) - requireValue.isRequire = true - end - func:setReturn(1, requireValue) -end - ----@param func emmyFunction ----@param values table ----@param index integer -function mt:callEmmyLoadFile(func, values, index) - if not values[index] then - values[index] = self:createValue('any', self:getDefaultSource()) - end - local str = values[index]:getLiteral() - if type(str) ~= 'string' then - return - end - local requireValue = self:tryRequireOne(str, values[index], 'loadfile') - if not requireValue then - requireValue = self:createValue('any', self:getDefaultSource()) - requireValue:set('cross file', true) - end - func:setReturn(1, requireValue) -end - ----@param func emmyFunction ----@param values table ----@param index integer ----@param source source -function mt:callEmmyPCall(func, values, index, source) - local funcValue = values[index] - if not funcValue then - return - end - local realFunc = funcValue:getFunction() - if not realFunc then - return - end - local argList = multi() - values:eachValue(function (i, v) - if i > index then - argList:push(v) - end - end) - self:call(funcValue, argList, source) - if realFunc ~= func then - func:setReturn(1, self:createValue('boolean', source)) - realFunc:getReturn():eachValue(function (i, v) - func:setReturn(i + 1, v) - end) - end -end - ----@param func emmyFunction ----@param values table ----@param index integer -function mt:callEmmyRequire(func, values, index) - if not values[index] then - values[index] = self:createValue('any', self:getDefaultSource()) - end - local strValue = values[index] - local strSource = strValue:getSource() - if not strSource then - return nil - end - local str = strValue:getLiteral() - local raw = self.text:sub(strSource.start, strSource.finish) - str = plugin.call('OnRequirePath', str, raw) or str - local lib = library.library[str] - if lib then - local value = libraryBuilder.value(lib) - value:markGlobal() - func:setReturn(1, value) - return - else - local requireValue = self:tryRequireOne(str, strValue, 'require') - if not requireValue then - requireValue = self:createValue('any', self:getDefaultSource()) - requireValue:set('cross file', true) - end - func:setReturn(1, requireValue) - end -end diff --git a/server/src/vm/value.lua b/server/src/vm/value.lua deleted file mode 100644 index 5de0d8e8..00000000 --- a/server/src/vm/value.lua +++ /dev/null @@ -1,634 +0,0 @@ -local libraryBuilder = require 'vm.library' -local library = require 'core.library' -local listMgr = require 'vm.list' -local config = require 'config' - -local Sort = 0 -local Watch = setmetatable({}, {__mode = 'kv'}) -local TypeLevel = { - ['table'] = 1.0, - ['function'] = 0.9, - ['string'] = 0.8, - ['integer'] = 0.7, - ['number'] = 0.6, -} - ----@class value -local mt = {} -mt.__index = mt -mt.type = 'value' -mt.uri = '' -mt._global = false - -local function create (tp, source, literal) - if tp == '...' then - error('Value type cant be ...') - end - if not source then - error('No source') - end - local id = source.id - if not id then - error('Not instanted source') - end - local self = setmetatable({ - source = id, - _type = {}, - _literal = literal, - _info = {}, - }, mt) - if type(tp) == 'table' then - for i = 1, #tp do - self:setType(tp[i], 1.0 / #tp) - end - else - self:setType(tp, 1.0) - end - Watch[self] = true - return self -end - -function mt:setType(tp, rate) - if type(tp) == 'table' then - for _, ctp in ipairs(tp) do - self:setType(ctp, rate) - end - return - end - if tp == '...' then - error('Value type cant be ...') - end - if not tp then - tp = 'nil' - end - if tp == 'any' or tp == 'nil' then - rate = 0.0 - end - if tp == 'integer' then - local version = config.config.runtime.version - if version ~= 'Lua 5.3' and version ~= 'Lua 5.4' then - tp = 'number' - end - end - local current = self._type[tp] or 0.0 - if rate > current then - self._type[tp] = rate - end -end - -function mt:getType() - if self:getEmmy() then - return self:getEmmy():getType(), 1.0 - end - if not self._type then - return 'nil', 0.0 - end - local mRate = 0.0 - local mType - for tp, rate in pairs(self._type) do - if rate > mRate then - mRate = rate - mType = tp - elseif rate == mRate then - local level1 = TypeLevel[tp] or 0.0 - local level2 = TypeLevel[mType] or 0.0 - if level1 > level2 then - mRate = rate - mType = tp - end - end - end - return mType or 'any', mRate -end - -function mt:rawSet(index, value, source) - if index == nil then - return - end - if not self._child then - self._child = {} - end - if self._child[index] then - if self._global then - self._child[index]:mergeValue(value) - else - self._child[index]:mergeType(value) - self._child[index]:mergeInfo(value) - end - self._child[index] = value - else - self._child[index] = value - end - self:addInfo('set child', source, index, self._child[index]) - if self._global then - self._child[index]:markGlobal() - end -end - -function mt:rawGet(index) - if not self._child then - return nil - end - self:flushChild() - local child = self._child[index] - if not child then - return nil - end - return child -end - -function mt:setChild(index, value, source) - if index == nil then - return - end - self:setType('table', 0.5) - self:rawSet(index, value, source) - return value -end - -function mt:getLibChild(index) - local tp = self:getType() - local lib = library.object[tp] - if lib then - local childs = libraryBuilder.child(lib) - return childs[index] - end - return nil -end - -function mt:eachLibChild(callback) - local tp = self:getType() - local lib = library.object[tp] - if lib then - local childs = libraryBuilder.child(lib) - for k, v in pairs(childs) do - callback(k, v) - end - end -end - -function mt:getChild(index, source) - self:setType('table', 0.5) - local parent = self - local value - -- 最多检查3层 __index - for _ = 1, 3 do - value = parent:rawGet(index) - if value then - break - end - local method = parent:getMetaMethod('__index') - if not method then - value = parent:getLibChild(index) - break - end - parent = method - end - if not value and source then - local emmy = self:getEmmy() - if emmy then - if emmy.type == 'emmy.arrayType' then - if type(index) == 'number' then - value = create(emmy:getName(), source) - end - elseif emmy.type == 'emmy.tableType' then - value = create(emmy:getValueType():getType(), source) - end - end - if not value then - value = create('any', source) - end - self:setChild(index, value) - value.uri = self.uri - end - return value -end - -function mt:setMetaTable(metatable) - local source = metatable:getSource() - if not source then - return - end - source:bindMetatable(metatable) - self._meta = metatable.source -end - -function mt:getMetaTable() - if not self._meta then - return nil - end - local metaSource = listMgr.get(self._meta) - if not metaSource then - self._meta = nil - return nil - end - return metaSource:bindMetatable() -end - -function mt:getMetaMethod(name) - local meta = self:getMetaTable() - if not meta then - return nil - end - return meta:rawGet(name) -end - -function mt:flushChild() - if not self._child then - return nil - end - -- 非全局值不会出现dead child - if not self._global then - return - end - local listVersion = listMgr.getVersion() - if self._flushVersion == listVersion then - return - end - self._flushVersion = listVersion - local alived = {} - local infos = self._info - local count = 0 - for srcId, info in pairs(infos) do - local src = listMgr.get(srcId) - if src then - if info.type == 'set child' or info.type == 'get child' then - if info[1] then - alived[info[1]] = true - end - end - count = count + 1 - else - infos[srcId] = nil - end - end - infos._count = count - infos._limit = count * 1.1 + 10 - infos._version = listMgr.getVersion() - for index in pairs(self._child) do - if not alived[index] then - self._child[index] = nil - end - end -end - -function mt:rawEach(callback, mark) - if not self._child then - return nil - end - self:flushChild() - for index, value in pairs(self._child) do - if mark then - if mark[index] then - goto CONTINUE - end - mark[index] = true - end - local res = callback(index, value) - if res ~= nil then - return res - end - ::CONTINUE:: - end - return nil -end - -function mt:eachChild(callback) - local mark = {} - local parent = self - -- 最多检查3层 __index - for _ = 1, 3 do - local res = parent:rawEach(callback, mark) - if res ~= nil then - return res - end - local method = parent:getMetaMethod('__index') - if not method then - return parent:eachLibChild(callback) - end - parent = method - end -end - -function mt:mergeType(value) - if self == value then - return - end - if not value then - return - end - if self._emmy and not value._emmy then - value._emmy = self._emmy - return - elseif not self._emmy and value._emmy then - self._emmy = value._emmy - return - end - if value._type then - for tp, rate in pairs(value._type) do - self:setType(tp, rate) - end - end - value._type = self._type -end - -function mt:mergeInfo(value) - if self == value then - return - end - if not value then - return - end - local infos = self._info - for srcId, info in pairs(value._info) do - local src = listMgr.get(srcId) - if src and not infos[srcId] then - infos[srcId] = info - infos._count = (infos._count or 0) + 1 - end - end - value._info = infos -end - -function mt:mergeValue(value) - if self == value then - return - end - if not value then - return - end - local list = {self, value} - local pos = 1 - while true do - local a, b = list[pos], list[pos+1] - if not a then - break - end - pos = pos + 2 - list[a] = true - list[b] = true - a:mergeType(b) - a:mergeInfo(b) - - a:flushChild() - b:flushChild() - local global = a._global or b._global - if b._child then - if not a._child then - a._child = {} - end - for k, bc in pairs(b._child) do - local ac = a._child[k] - if ac and ac ~= bc and global then - if list[ac] and list[bc] then - else - list[#list+1] = ac - list[#list+1] = bc - end - end - a._child[k] = bc - end - end - b._child = a._child - if global then - a:markGlobal() - b:markGlobal() - end - - if b._meta then - a._meta = b._meta - end - if b._func then - a._func = b._func - end - if b._lib then - a._lib = b._lib - end - if b.uri then - a.uri = b.uri - end - end -end - -function mt:addInfo(tp, source, ...) - if not source then - return - end - if not source.start then - error('Miss start: ' .. table.dump(source)) - end - local id = source.id - if not id then - error('Not instanted source') - end - if not tp then - error('Miss info type') - end - - local infos = self._info - if infos[id] then - return - end - Sort = Sort + 1 - local info = { - type = tp, - source = id, - _sort = Sort, - ... - } - infos[id] = info - infos._count = (infos._count or 0) + 1 - local version = listMgr.getVersion() - -- 只有全局值需要压缩info - if self._global and infos._count > (infos._limit or 10) and infos._version ~= version then - local count = 0 - for srcId in pairs(infos) do - local src = listMgr.get(srcId) - if src then - count = count + 1 - else - infos[srcId] = nil - end - end - infos._count = count - infos._limit = count * 1.1 + 10 - infos._version = version - end -end - -function mt:eachInfo(callback) - local clock = os.clock() - local infos = self._info - local list = {} - for srcId, info in pairs(infos) do - local src = listMgr.get(srcId) - if src then - list[#list+1] = info - else - infos[srcId] = nil - end - end - infos._count = #list - infos._limit = infos._count * 1.1 + 10 - infos._version = listMgr.getVersion() - --local clock2 = os.clock() - --table.sort(list, function (a, b) - -- return a._sort < b._sort - --end) - local passed = os.clock() - clock - if passed > 0.1 then - log.warn(('eachInfo takes: [%.3f]sec, #list: %d'):format(passed, #list)) - end - for i = 1, #list do - local info = list[i] - local res = callback(info, listMgr.get(info.source)) - if res ~= nil then - return res - end - end - return nil -end - -function mt:setFunction(func) - self._func = func.id - if self._global then - func:markGlobal() - end -end - -function mt:getFunction() - local id = self._func - local func = listMgr.get(id) - if not func then - return nil - end - if func._removed then - return nil - end - if not func:getSource() then - func = nil - listMgr.clear(id) - end - return func -end - -function mt:setLib(lib) - self._lib = lib -end - -function mt:getLib() - return self._lib -end - -function mt:getLiteral() - return self._literal -end - -function mt:set(name, v) - if not self._flag then - self._flag = {} - end - self._flag[name] = v -end - -function mt:get(name) - if not self._flag then - return nil - end - return self._flag[name] -end - -function mt:getSource() - return listMgr.get(self.source) -end - -function mt:markGlobal() - if self._global then - return - end - self._global = true - self:rawEach(function (index, value) - value:markGlobal() - end) - local func = self:getFunction() - if func then - func:markGlobal() - end -end - -function mt:isGlobal() - return self._global -end - -function mt:setEmmy(emmy) - if not emmy then - return - end - if emmy.type == 'emmy.class' then - ---@type EmmyClass - local emmyClass = emmy - emmyClass:setValue(self) - emmyClass:eachChild(function (obj) - local value = obj:getValue() - if value then - value:mergeValue(self) - end - end) - emmyClass:eachField(function (field) - local name = field:getName() - local value = field:bindValue() - self:setChild(name, value, field:getSource()) - end) - elseif emmy.type == 'emmy.type' then - ---@type EmmyType - local emmyType = emmy - emmyType:setValue(self) - emmyType:eachClass(function (class) - if class then - self:mergeValue(class:getValue()) - end - end) - elseif emmy.type == 'emmy.arrayType' then - ---@type EmmyArrayType - local emmyArrayType = emmy - emmyArrayType:setValue(self) - elseif emmy.type == 'emmy.tableType' then - ---@type EmmyTableType - local emmyTableType = emmy - emmyTableType:setValue(self) - elseif emmy.type == 'emmy.functionType' then - ---@type EmmyFunctionType - local emmyFuncType = emmy - emmyFuncType:setValue(self) - self:setFunction(emmyFuncType:bindFunction()) - else - return - end - self._emmy = emmy - self:markGlobal() -end - -function mt:getEmmy() - if not self._emmy then - return nil - end - local source = self._emmy.source - if not listMgr.get(source) then - self._emmy = nil - return nil - end - return self._emmy -end - -function mt:setComment(comment) - self._comment = comment -end - -function mt:getComment(comment) - return self._comment -end - -return { - create = create, - watch = Watch, -} diff --git a/server/src/vm/vm.lua b/server/src/vm/vm.lua deleted file mode 100644 index 36ad78c9..00000000 --- a/server/src/vm/vm.lua +++ /dev/null @@ -1,1334 +0,0 @@ -local library = require 'core.library' -local valueMgr = require 'vm.value' -local localMgr = require 'vm.local' -local createLabel = require 'vm.label' -local functionMgr = require 'vm.function' -local sourceMgr = require 'vm.source' -local buildGlobal = require 'vm.global' -local createMulti = require 'vm.multi' -local libraryBuilder = require 'vm.library' -local emmyMgr = require 'emmy.manager' -local config = require 'config' -local mt = require 'vm.manager' -local plugin = require 'plugin' - -require 'vm.module' -require 'vm.raw' -require 'vm.pcall' -require 'vm.ipairs' -require 'vm.emmy' -require 'vm.special' - --- TODO source测试 ---rawset(_G, 'CachedSource', setmetatable({}, { __mode = 'kv' })) - -function mt:getDefaultSource() - return self:instantSource { - start = 0, - finish = 0, - } -end - -function mt:scopePush(source) - self.currentFunction:push(source) -end - -function mt:scopePop() - self.currentFunction:pop() -end - -function mt:buildTable(source) - local tbl = self:createValue('table', source) - if not source then - return tbl - end - local n = 0 - for index, obj in ipairs(source) do - local emmy = self:getEmmy() - if obj.type == 'pair' then - local value = self:getFirstInMulti(self:getExp(obj[2])) - if value then - local key = obj[1] - self:instantSource(obj) - self:instantSource(key) - key:bindValue(value, 'set') - value:setEmmy(emmy) - if key.type == 'index' then - local index = self:getIndex(key) - key:set('parent', tbl) - tbl:setChild(index, value, key) - else - if key.type == 'name' then - key:set('parent', tbl) - key:set('table index', true) - tbl:setChild(key[1], value, key) - end - end - end - elseif obj.type:sub(1, 4) == 'emmy' then - self:doEmmy(obj) - else - local value = self:getExp(obj) - if value.type == 'multi' then - if index == #source then - value:eachValue(function (_, v) - n = n + 1 - tbl:setChild(n, v, obj) - end) - else - n = n + 1 - local v = self:getFirstInMulti(value) - tbl:setChild(n, v, obj) - end - else - n = n + 1 - tbl:setChild(n, value, obj) - end - -- 处理写了一半的 key = value,把name类的数组元素视为哈希键 - if obj.type == 'name' then - obj:set('table index', true) - end - end - end - return tbl -end - -function mt:runFunction(func) - func:run(self) - - if not func:getSource() then - return - end - - if func:needSkip() then - return - end - - -- 暂时使用这种方式激活参数的source - for _, arg in ipairs(func.args) do - if arg:getSource() ~= func:getObject() then - self:bindLocal(arg:getSource(), arg, 'local') - end - end - - local originFunction = self:getCurrentFunction() - self:setCurrentFunction(func) - func:push(func:getSource()) - func:markChunk() - - self:doActions(func:getSource()) - - func:pop() - self:setCurrentFunction(originFunction) -end - -function mt:buildFunction(exp) - if exp and exp:bindFunction() then - return exp:bindFunction() - end - - local value = self:createFunction(exp) - - if not exp then - return value - end - - exp:bindFunction(value) - local func = value:getFunction() - - self:eachLocal(function (name, loc) - func:saveUpvalue(name, loc) - end) - - return value -end - -function mt:forList(list, callback) - if not list then - return - end - if list.type == 'list' then - for i = 1, #list do - callback(list[i]) - end - else - callback(list) - end -end - -function mt:callSetMetaTable(func, values, source) - if not values[1] then - values[1] = self:createValue('any', self:getDefaultSource()) - end - if not values[2] then - values[2] = self:createValue('any', self:getDefaultSource()) - end - func:setReturn(1, values[1]) - values[1]:setMetaTable(values[2]) -end - -function mt:tryRequireOne(str, strValue, mode) - if not self.lsp or not self.lsp.workspace then - return nil - end - local strSource = strValue:getSource() - if not strSource then - return nil - end - if type(str) == 'string' then - -- 支持 require 'xxx' 的转到定义 - self:instantSource(strSource) - local uri - if mode == 'require' then - uri = self.lsp.workspace:searchPath(self:getUri(), str) - elseif mode == 'loadfile' then - uri = self.lsp.workspace:loadPath(self:getUri(), str) - elseif mode == 'dofile' then - uri = self.lsp.workspace:loadPath(self:getUri(), str) - end - if not uri then - return nil - end - - strSource:set('target uri', uri) - self.lsp:compileChain(self:getUri(), uri) - return self.lsp.chain:get(uri) - end - return nil -end - -function mt:callRequire(func, values) - if not values[1] then - values[1] = self:createValue('any', self:getDefaultSource()) - end - local strValue = values[1] - local strSource = strValue:getSource() - if not strSource then - return nil - end - local str = strValue:getLiteral() - local raw = self.text:sub(strSource.start, strSource.finish) - str = plugin.call('OnRequirePath', str, raw) or str - local lib = library.library[str] - if lib then - local value = libraryBuilder.value(lib) - value:markGlobal() - func:setReturn(1, value) - return - else - local requireValue = self:tryRequireOne(str, values[1], 'require') - if not requireValue then - requireValue = self:createValue('any', self:getDefaultSource()) - requireValue:set('cross file', true) - end - func:setReturn(1, requireValue) - end -end - -function mt:callLoadFile(func, values) - if not values[1] then - values[1] = self:createValue('any', self:getDefaultSource()) - end - local strValue = values[1] - local requireValue = self:tryRequireOne(strValue:getLiteral(), values[1], 'loadfile') - if not requireValue then - requireValue = self:createValue('any', self:getDefaultSource()) - requireValue:set('cross file', true) - end - func:setReturn(1, requireValue) -end - -function mt:callDoFile(func, values) - if not values[1] then - values[1] = self:createValue('any', self:getDefaultSource()) - end - local strValue = values[1] - local requireValue = self:tryRequireOne(strValue:getLiteral(), values[1], 'dofile') - if not requireValue then - requireValue = self:createValue('any', self:getDefaultSource()) - requireValue.isRequire = true - end - func:setReturn(1, requireValue) -end - -function mt:callLibrary(func, values, source, lib) - if lib.args then - for i, arg in ipairs(lib.args) do - local value = values[i] - if value and arg.type ~= '...' then - value:setType(arg.type, 0.6) - end - end - end - if lib.returns then - for i, rtn in ipairs(lib.returns) do - if rtn.type == '...' then - --func:getReturn(i):setType('any', 0.0) - else - if rtn.type == 'boolean' or rtn.type == 'number' or rtn.type == 'integer' or rtn.type == 'string' then - func:setReturn(i, self:createValue(rtn.type, self:getDefaultSource())) - end - local value = func:getReturn(i) - if value then - value:setType(rtn.type or 'any', 0.6) - end - end - end - end - if lib.special then - if lib.special == 'setmetatable' then - self:callSetMetaTable(func, values, source) - elseif lib.special == 'require' then - self:callRequire(func, values) - elseif lib.special == 'loadfile' then - self:callLoadFile(func, values) - elseif lib.special == 'dofile' then - self:callDoFile(func, values) - elseif lib.special == 'module' then - self:callModuel(func, values) - elseif lib.special == 'seeall' then - self:callSeeAll(func, values) - elseif lib.special == 'rawset' then - self:callRawSet(func, values, source) - elseif lib.special == 'rawget' then - self:callRawGet(func, values, source) - elseif lib.special == 'pcall' then - self:callPcall(func, values, source) - elseif lib.special == 'xpcall' then - self:callXpcall(func, values, source) - elseif lib.special == 'ipairs' then - self:callIpairs(func, values, source) - elseif lib.special == '@ipairs' then - self:callAtIpairs(func, values, source) - elseif lib.special == 'pairs' then - self:callPairs(func, values, source) - elseif lib.special == 'next' then - self:callNext(func, values, source) - end - else - -- 如果lib的参数中有function,则立即执行function - if lib.args then - local args - for i = 1, #lib.args do - local value = values[i] - if value and value:getFunction() then - if not args then - args = createMulti() - end - self:call(value, args, source) - end - end - end - end -end - -function mt:call(value, values, source) - local lib = value:getLib() - ---@type emmyFunction - local func = value:getFunction() - value:setType('function', 0.5) - if not func then - return - end - self:instantSource(source) - if lib then - self:callLibrary(func, values, source, lib) - else - if func:getSource() then - if not source:get 'called' then - source:set('called', true) - func:setArgs(values) - self:runFunction(func) - end - else - func:mergeReturn(1, self:createValue('any', source)) - end - if func:getEmmyParams() then - self:callEmmySpecial(func, values, source) - end - end - - return func:getReturn() -end - -function mt:createValue(tp, source, literal) - local value = valueMgr.create(tp, source, literal) - value.uri = self:getUri() - return value -end - -function mt:getName(name, source) - if source then - self:instantSource(source) - if source:bindLocal() then - local loc = source:bindLocal() - return loc:getValue() - end - end - local loc = self:loadLocal(name) - if loc then - source:bindLocal(loc, 'get') - return loc:getValue() - end - local global = source:bindValue() - if global then - return global - end - local ENV - if self.envType == '_ENV' then - ENV = self:loadLocal('_ENV') - else - ENV = self:loadLocal('@ENV') - end - local ENVValue = ENV:getValue() - ENVValue:addInfo('get child', source, name) - global = ENVValue:getChild(name, source) - source:bindValue(global, 'get') - source:set('global', true) - source:set('parent', ENVValue) - if not global:getLib() then - if self.lsp then - self.lsp.global:markGet(self:getUri()) - end - end - return global -end - -function mt:setName(name, source, value) - self:instantSource(source) - local loc = self:loadLocal(name) - if loc then - loc:setValue(value) - source:bindLocal(loc, 'set') - return - end - local global = source:bindValue() - if global then - return global - end - local ENV - if self.envType == '_ENV' then - ENV = self:loadLocal('_ENV') - else - ENV = self:loadLocal('@ENV') - end - local ENVValue = ENV:getValue() - source:bindValue(value, 'set') - ENVValue:setChild(name, value, source) - source:set('global', true) - source:set('parent', ENVValue) - if self.lsp then - self.lsp.global:markSet(self:getUri()) - end -end - -function mt:getIndex(source) - local child = source[1] - if child.type == 'name' then - local value = self:getName(child[1], child) - child:set('in index', source) - return value - elseif child.type == 'string' or child.type == 'number' or child.type == 'boolean' then - self:instantSource(child) - child:set('in index', source) - return child[1] - else - local index = self:getExp(child) - return self:getFirstInMulti(index) - end -end - -function mt:unpackList(list) - local values = createMulti() - local exps = createMulti() - if not list then - return values - end - if list.type == 'list' or list.type == 'call' or list.type == 'return' then - for i, exp in ipairs(list) do - self:instantSource(exp) - exps:push(exp) - if exp.type == '...' then - values:merge(self:loadDots()) - break - end - local value = self:getExp(exp) - if value.type == 'multi' then - if i == #list then - value:eachValue(function (_, v) - values:push(v) - end) - else - values:push(self:getFirstInMulti(value)) - end - else - values:push(value) - end - end - elseif list.type == '...' then - self:instantSource(list) - exps:push(list) - values:merge(self:loadDots()) - else - self:instantSource(list) - exps:push(list) - local value = self:getExp(list) - if value.type == 'multi' then - value:eachValue(function (_, v) - values:push(v) - end) - else - values:push(value) - end - end - return values, exps -end - -function mt:getFirstInMulti(multi) - if not multi then - return multi - end - if multi.type == 'multi' then - return self:getFirstInMulti(multi[1]) - else - return multi - end -end - -function mt:getSimple(simple, max) - self:instantSource(simple) - local first = simple[1] - self:instantSource(first) - local value = self:getExp(first) - value = self:getFirstInMulti(value) or valueMgr.create('nil', self:getDefaultSource()) - first:bindValue(value, 'get') - if not max then - max = #simple - elseif max < 0 then - max = #simple + 1 + max - end - local object - for i = 2, max do - local source = simple[i] - self:instantSource(source) - source:set('simple', simple) - value = self:getFirstInMulti(value) or valueMgr.create('nil', self:getDefaultSource()) - - if source.type == 'call' then - local values, args = self:unpackList(source) - local func = value - if object then - table.insert(values, 1, object) - table.insert(args, 1, simple[i-3]) - source:set('has object', true) - end - object = nil - source:bindCall(args) - value = self:call(func, values, source) or valueMgr.create('any', self:getDefaultSource()) - elseif source.type == 'index' then - local child = source[1] - local index = self:getIndex(source) - child:set('parent', value) - value:addInfo('get child', source, index) - value = value:getChild(index, source) - source:bindValue(value, 'get') - elseif source.type == 'name' then - source:set('parent', value) - source:set('object', object) - value:addInfo('get child', source, source[1]) - value = value:getChild(source[1], source) - source:bindValue(value, 'get') - elseif source.type == ':' then - object = value - source:set('parent', value) - source:set('object', object) - elseif source.type == '.' then - source:set('parent', value) - end - end - return value -end - -function mt:isTrue(v) - if v:getType() == 'nil' then - return false - end - if v:getType() == 'boolean' and not v:getLiteral() then - return false - end - return true -end - -function mt:getBinary(exp) - self:instantSource(exp) - local v1 = self:getExp(exp[1]) - local v2 = self:getExp(exp[2]) - v1 = self:getFirstInMulti(v1) or valueMgr.create('nil', exp[1]) - v2 = self:getFirstInMulti(v2) or valueMgr.create('nil', exp[2]) - local op = exp.op - -- TODO 搜索元方法 - if op == 'or' then - if self:isTrue(v1) then - return v1 - else - return v2 - end - elseif op == 'and' then - if self:isTrue(v1) then - return v2 - else - return v1 - end - elseif op == '<=' - or op == '>=' - or op == '<' - or op == '>' - then - v1:setType('number', 0.5) - v2:setType('number', 0.5) - v1:setType('string', 0.1) - v2:setType('string', 0.1) - return self:createValue('boolean', exp) - elseif op == '~=' - or op == '==' - then - return self:createValue('boolean', exp) - elseif op == '|' - or op == '~' - or op == '&' - or op == '<<' - or op == '>>' - then - v1:setType('integer', 0.5) - v2:setType('integer', 0.5) - v1:setType('number', 0.5) - v2:setType('number', 0.5) - v1:setType('string', 0.1) - v2:setType('string', 0.1) - if math.type(v1:getLiteral()) == 'integer' and math.type(v2:getLiteral()) == 'integer' then - if op == '|' then - return self:createValue('integer', exp, v1:getLiteral() | v2:getLiteral()) - elseif op == '~' then - return self:createValue('integer', exp, v1:getLiteral() ~ v2:getLiteral()) - elseif op == '&' then - return self:createValue('integer', exp, v1:getLiteral() &v2:getLiteral()) - elseif op == '<<' then - return self:createValue('integer', exp, v1:getLiteral() << v2:getLiteral()) - elseif op == '>>' then - return self:createValue('integer', exp, v1:getLiteral() >> v2:getLiteral()) - end - end - return self:createValue('integer', exp) - elseif op == '..' then - v1:setType('string', 0.5) - v2:setType('string', 0.5) - v1:setType('number', 0.1) - v2:setType('number', 0.1) - if type(v1:getLiteral()) == 'string' and type(v2:getLiteral()) == 'string' then - return self:createValue('string', exp, v1:getLiteral() .. v2:getLiteral()) - end - return self:createValue('string', exp) - elseif op == '+' - or op == '-' - or op == '*' - or op == '/' - or op == '^' - or op == '%' - or op == '//' - then - v1:setType('number', 0.5) - v2:setType('number', 0.5) - if type(v1:getLiteral()) == 'number' and type(v2:getLiteral()) == 'number' then - if op == '+' then - return self:createValue('number', exp, v1:getLiteral() + v2:getLiteral()) - elseif op == '-' then - return self:createValue('number', exp, v1:getLiteral() - v2:getLiteral()) - elseif op == '*' then - return self:createValue('number', exp, v1:getLiteral() * v2:getLiteral()) - elseif op == '/' then - if v2:getLiteral() ~= 0 then - return self:createValue('number', exp, v1:getLiteral() / v2:getLiteral()) - end - elseif op == '^' then - return self:createValue('number', exp, v1:getLiteral() ^ v2:getLiteral()) - elseif op == '%' then - if v2:getLiteral() ~= 0 then - return self:createValue('number', exp, v1:getLiteral() % v2:getLiteral()) - end - elseif op == '//' then - if v2:getLiteral() ~= 0 then - return self:createValue('number', exp, v1:getLiteral() // v2:getLiteral()) - end - end - end - return self:createValue('number', exp) - end - return nil -end - -function mt:getUnary(exp) - self:instantSource(exp) - local v1 = self:getExp(exp[1]) - v1 = self:getFirstInMulti(v1) or self:createValue('nil', exp[1]) - local op = exp.op - -- TODO 搜索元方法 - if op == 'not' then - return self:createValue('boolean', exp) - elseif op == '#' then - v1:setType('table', 0.5) - v1:setType('string', 0.5) - if type(v1:getLiteral()) == 'string' then - return self:createValue('integer', exp, #v1:getLiteral()) - end - return self:createValue('integer', exp) - elseif op == '-' then - v1:setType('number', 0.5) - if type(v1:getLiteral()) == 'number' then - return self:createValue('number', exp, -v1:getLiteral()) - end - return self:createValue('number', exp) - elseif op == '~' then - v1:setType('integer', 0.5) - if math.type(v1:getLiteral()) == 'integer' then - return self:createValue('integer', exp, ~v1:getLiteral()) - end - return self:createValue('integer', exp) - end - return nil -end - -function mt:getExp(exp) - self:instantSource(exp) - local tp = exp.type - if tp == 'nil' then - return self:createValue('nil', exp) - elseif tp == 'string' then - return self:createValue('string', exp, exp[1]) - elseif tp == 'boolean' then - return self:createValue('boolean', exp, exp[1]) - elseif tp == 'number' then - return self:createValue('number', exp, exp[1]) - elseif tp == 'name' then - local value = self:getName(exp[1], exp) - return value - elseif tp == 'simple' then - return self:getSimple(exp) - elseif tp == 'index' then - return self:getIndex(exp) - elseif tp == 'binary' then - return self:getBinary(exp) - elseif tp == 'unary' then - return self:getUnary(exp) - elseif tp == 'function' then - return self:buildFunction(exp) - elseif tp == 'table' then - return self:buildTable(exp) - elseif tp == '...' then - return self:loadDots() - elseif tp == 'list' then - return self:getMultiByList(exp) - end - error('Unkown exp type: ' .. tostring(tp)) -end - -function mt:getMultiByList(list) - local multi = createMulti() - for i, exp in ipairs(list) do - multi:push(self:getExp(exp), i == #list) - end - return multi -end - -function mt:doDo(action) - self:instantSource(action) - self:scopePush(action) - self:doActions(action) - self:scopePop() -end - -function mt:doReturn(action) - if #action == 0 then - return - end - self:instantSource(action) - local values = self:unpackList(action) - local func = self:getCurrentFunction() - values:eachValue(function (n, value) - value.uri = self:getUri() - func:mergeReturn(n, value) - local source = action[n] or value:getSource() - if not source or source.start == 0 then - source = self:getDefaultSource() - end - value:addInfo('return', source) - end) -end - -function mt:doLabel(source) - local name = source[1] - local label = self:loadLabel(name) - if label then - self:bindLabel(source, label, 'set') - else - label = self:createLabel(name, source, 'set') - end -end - -function mt:createLabel(name, source, action) - local label = self:bindLabel(source) - if label then - self:saveLabel(label) - return label - end - - label = createLabel(name, source) - self:saveLabel(label) - self:bindLabel(source, label, action) - return label -end - -function mt:doGoTo(source) - local name = source[1] - local label = self:loadLabel(name) - if label then - self:bindLabel(source, label, 'get') - else - label = self:createLabel(name, source, 'get') - end -end - -function mt:setOne(var, value, emmy, comment) - if not value then - value = valueMgr.create('nil', self:getDefaultSource()) - end - value:setEmmy(emmy) - value:setComment(comment) - self:instantSource(var) - if var.type == 'name' then - self:setName(var[1], var, value) - elseif var.type == 'simple' then - local parent = self:getSimple(var, -2) - parent = self:getFirstInMulti(parent) - local key = var[#var] - self:instantSource(key) - key:set('simple', var) - if key.type == 'index' then - local index = self:getIndex(key) - key[1]:set('parent', parent) - parent:setChild(index, value, key[1]) - elseif key.type == 'name' then - local index = key[1] - key:set('parent', parent) - parent:setChild(index, value, key) - end - key:bindValue(value, 'set') - end -end - -function mt:doSet(action) - local emmy = self:getEmmy() - local comment = self:getEmmyComment() - if not action[2] then - return - end - self:instantSource(action) - -- 要先计算值 - local vars = action[1] - local exps = action[2] - local value = self:getExp(exps) - local values = {} - if value.type == 'multi' then - if not emmy then - emmy = value:getEmmy() - end - value:eachValue(function (i, v) - values[i] = v - end) - else - values[1] = value - end - local i = 0 - self:forList(vars, function (var) - i = i + 1 - self:setOne(var, values[i], emmy, comment) - end) -end - -function mt:doLocal(action) - local emmy = self:getEmmy() - local comment = self:getEmmyComment() - self:instantSource(action) - local vars = action[1] - local exps = action[2] - local values - if exps then - local value = self:getExp(exps) - values = {} - if value.type == 'multi' then - if not emmy then - emmy = value:getEmmy() - end - value:eachValue(function (i, v) - values[i] = v - end) - else - values[1] = value - end - end - local i = 0 - self:forList(vars, function (key) - i = i + 1 - local value - if values then - value = values[i] - end - self:createLocal(key[1], key, value, emmy, comment) - end) -end - -function mt:doIf(action) - self:instantSource(action) - for _, block in ipairs(action) do - if block.filter then - self:getExp(block.filter) - end - - self:scopePush(block) - self:doActions(block) - self:scopePop() - end -end - -function mt:doLoop(action) - self:instantSource(action) - local min = self:getFirstInMulti(self:getExp(action.min)) - self:getExp(action.max) - if action.step then - self:getExp(action.step) - end - - self:scopePush(action) - self:createLocal(action.arg[1], action.arg, min) - self:doActions(action) - self:scopePop() -end - -function mt:doIn(action) - local emmyParams = self:getEmmyParams() - self:instantSource(action) - local args = self:unpackList(action.exp) - - self:scopePush(action) - local func = table.remove(args, 1) or valueMgr.create('any', self:getDefaultSource()) - local values = self:call(func, args, action) or createMulti() - self:forList(action.arg, function (arg) - self:instantSource(arg) - local value = table.remove(values, 1) or self:createValue('nil', arg) - if emmyParams then - for i = #emmyParams, 1, -1 do - local emmyParam = emmyParams[i] - if emmyParam and emmyParam:getName() == arg[1] then - value:setEmmy(emmyParam:bindType()) - end - end - end - self:createLocal(arg[1], arg, value) - end) - - self:doActions(action) - - self:scopePop() -end - -function mt:doWhile(action) - self:instantSource(action) - self:getExp(action.filter) - - self:scopePush(action) - self:doActions(action) - self:scopePop() -end - -function mt:doRepeat(action) - self:instantSource(action) - self:scopePush(action) - self:doActions(action) - self:getExp(action.filter) - self:scopePop() -end - -function mt:doFunction(action) - self:instantSource(action) - local name = action.name - if name then - self:instantSource(name) - if name.type == 'simple' then - local parent = self:getSimple(name, -2) - if name[#name-1].type == ':' then - local value = self:buildFunction(action) - local source = name[#name] - self:instantSource(source) - source:set('simple', name) - source:set('parent', parent) - source:set('object', parent) - if source.type == 'index' then - local index = self:getIndex(source) - parent:setChild(index, value, source[1]) - elseif source.type == 'name' then - local index = source[1] - parent:setChild(index, value, source) - end - source:bindValue(value, 'set') - - local func = value:getFunction() - if func then - if #name == 3 then - -- function x:b() - local loc = self:loadLocal(name[1][1]) - if loc then - func:setObject(parent, loc:getSource()) - else - func:setObject(parent, name[#name-2]) - end - else - func:setObject(parent, name[#name-2]) - end - end - else - local value = self:buildFunction(action) - local source = name[#name] - self:instantSource(source) - source:set('simple', name) - source:set('parent', parent) - if source.type == 'index' then - local index = self:getIndex(source) - parent:setChild(index, value, source[1]) - elseif source.type == 'name' then - local index = source[1] - parent:setChild(index, value, source) - end - source:bindValue(value, 'set') - end - else - local value = self:buildFunction(action) - self:setName(name[1], name, value) - end - else - self:buildFunction(action) - end -end - -function mt:doLocalFunction(action) - self:instantSource(action) - local name = action.name - if name then - self:instantSource(name) - if name.type == 'simple' then - self:doFunction(action) - else - local loc = self:createLocal(name[1], name) - local func = self:buildFunction(action) - func:addInfo('local', name) - loc:setValue(func) - name:bindValue(func, 'local') - end - end -end - -function mt:doAction(action) - if not action then - -- Skip - return - end - if coroutine.isyieldable() then - if self.lsp:isNeedCompile(self.uri) then - coroutine.yield() - if self._removed then - coroutine.yield('stop') - return - end - else - self:remove() - coroutine.yield('stop') - return - end - end - local tp = action.type - if tp:sub(1, 4) == 'emmy' then - self:doEmmy(action) - return - end - if tp == 'do' then - self:doDo(action) - elseif tp == 'break' then - elseif tp == 'return' then - self:doReturn(action) - elseif tp == 'label' then - self:doLabel(action) - elseif tp == 'goto' then - self:doGoTo(action) - elseif tp == 'set' then - self:doSet(action) - elseif tp == 'local' then - self:doLocal(action) - elseif tp == 'simple' then - -- call - self:getSimple(action) - action:set('as action', true) - elseif tp == 'if' then - self:doIf(action) - elseif tp == 'loop' then - self:doLoop(action) - elseif tp == 'in' then - self:doIn(action) - elseif tp == 'while' then - self:doWhile(action) - elseif tp == 'repeat' then - self:doRepeat(action) - elseif tp == 'function' then - self:doFunction(action) - elseif tp == 'localfunction' then - self:doLocalFunction(action) - else - self:getExp(action) - action:set('as action', true) - end - self:clearEmmy() -end - -function mt:doActions(actions) - for _, action in ipairs(actions) do - self:doAction(action) - end -end - -function mt:createFunction(source) - local value = self:createValue('function', source) - local func = functionMgr.create(source) - func:setEmmy(self:getEmmyParams(), self:getEmmyReturns(), self:getEmmyOverLoads()) - func:setComment(self:getEmmyComment()) - value:setFunction(func) - value:setType('function', 1.0) - if source:getUri() == self.uri then - self.funcs[#self.funcs+1] = func - end - return value -end - -function mt:callLeftFuncions() - for _, func in ipairs(self.funcs) do - if not func:hasRuned() then - self:runFunction(func) - end - end -end - -function mt:setCurrentFunction(func) - self.currentFunction = func -end - -function mt:getCurrentFunction() - return self.currentFunction -end - -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 - -function mt:eachLocal(callback) - return self.currentFunction:eachLocal(callback) -end - -function mt:saveLabel(label) - self.currentFunction:saveLabel(label) -end - -function mt:loadLabel(name) - return self.currentFunction:loadLabel(name) -end - -function mt:loadDots() - return self.currentFunction:loadDots() -end - -function mt:getUri() - return self.currentFunction and self.currentFunction:getUri() or self.uri -end - -function mt:instantSource(source) - if self:isRemoved() then - error('dead vm') - return nil - end - if sourceMgr.instant(source) then - source:setUri(self:getUri()) - self.sources[#self.sources+1] = source - --CachedSource[source] = true - end - return source -end - -function mt:bindLocal(source, loc, action) - if not source then - return - end - self:instantSource(source) - if loc then - source:bindLocal(loc, action) - else - return source:bindLocal() - end -end - -function mt:bindLabel(source, label, action) - self:instantSource(source) - if label then - source:bindLabel(label, action) - else - return source:bindLabel() - end -end - -function mt:createLocal(key, source, value, emmy, comment) - local loc = self:bindLocal(source) - if not value then - value = self:createValue('nil', source) - end - if loc then - loc:setValue(value) - loc:setEmmy(emmy) - self:saveLocal(key, loc) - return loc - end - - loc = localMgr.create(key, source, value, source.tags) - loc:setEmmy(emmy) - loc:setComment(comment) - self:saveLocal(key, loc) - self:bindLocal(source, loc, 'local') - loc:close(self:getCurrentFunction():getSource().finish) - value:addInfo('local', source) - return loc -end - -function mt:createUpvalue(key, source, value) - local loc = self:bindLocal(source) - if not value then - value = self:createValue('nil', source) - end - if loc then - loc:setValue(value) - self:saveUpvalue(key, loc) - return loc - 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) - self:setCurrentFunction(self.main:getFunction()) - if self.lsp then - self.main:getFunction():mergeReturn(1, self.lsp.chain:get(self.uri)) - end - -- 全局变量`_G` - local global = buildGlobal(self.lsp) - local env - if self.envType == '_ENV' then - -- 隐藏的上值`_ENV` - env = self:createUpvalue('_ENV', self:getDefaultSource(), global) - else - -- 为了实现方便,fenv也使用隐藏上值来实现 - -- 使用了非法标识符保证用户无法访问 - env = self:createUpvalue('@ENV', self:getDefaultSource(), global) - end - env:set('hide', true) - self.env = env -end - -function mt:eachSource(callback) - if self._removed then - return - end - local sources = self.sources - for i = 1, #sources do - local res = callback(sources[i]) - if res ~= nil then - return res - end - end -end - -function mt:isRemoved() - return self._removed == true -end - -function mt:remove() - if self._removed then - return - end - self._removed = true - for _, source in ipairs(self.sources) do - source:kill() - end - self.sources = nil - for _, func in ipairs(self.funcs) do - func:kill() - end - self.funcs = nil -end - -local function compile(vm, ast, lsp, uri) - -- 创建初始环境 - ast.uri = vm.uri - -- 根据运行版本决定环境实现方式 - if config.config.runtime.version == 'Lua 5.1' or config.config.runtime.version == 'LuaJIT' then - vm.envType = 'fenv' - else - vm.envType = '_ENV' - end - vm:instantSource(ast) - vm:createEnvironment(ast) - - -- 检查所有没有调用过的函数,调用一遍 - vm:callLeftFuncions() - - return vm -end - -return function (ast, lsp, uri, text) - if not ast then - return nil, 'Ast failed' - end - local vm = setmetatable({ - funcs = {}, - sources = {}, - main = nil, - env = nil, - emmy = nil, - ---@type emmyMgr - emmyMgr = lsp and lsp.emmy or emmyMgr(), - lsp = lsp, - uri = uri or '', - text = text or '', - }, mt) - local suc, res = xpcall(compile, log.error, vm, ast, lsp, uri) - if not suc then - vm:remove() - return nil, res - end - return res -end |