summaryrefslogtreecommitdiff
path: root/server/src/vm
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2019-11-22 23:26:32 +0800
committer最萌小汐 <sumneko@hotmail.com>2019-11-22 23:26:32 +0800
commitd0ff66c9abe9d6abbca12fd811e0c3cb69c1033a (patch)
treebb34518d70b85de7656dbdbe958dfa221a3ff3b3 /server/src/vm
parent0a2c2ad15e1ec359171fb0dd4c72e57c5b66e9ba (diff)
downloadlua-language-server-d0ff66c9abe9d6abbca12fd811e0c3cb69c1033a.zip
整理一下目录结构
Diffstat (limited to 'server/src/vm')
-rw-r--r--server/src/vm/chain.lua65
-rw-r--r--server/src/vm/emmy.lua372
-rw-r--r--server/src/vm/function.lua551
-rw-r--r--server/src/vm/global.lua25
-rw-r--r--server/src/vm/init.lua1
-rw-r--r--server/src/vm/ipairs.lua51
-rw-r--r--server/src/vm/label.lua75
-rw-r--r--server/src/vm/library.lua112
-rw-r--r--server/src/vm/list.lua30
-rw-r--r--server/src/vm/local.lua191
-rw-r--r--server/src/vm/manager.lua17
-rw-r--r--server/src/vm/module.lua56
-rw-r--r--server/src/vm/multi.lua83
-rw-r--r--server/src/vm/pcall.lua50
-rw-r--r--server/src/vm/raw.lua30
-rw-r--r--server/src/vm/source.lua183
-rw-r--r--server/src/vm/special.lua130
-rw-r--r--server/src/vm/value.lua634
-rw-r--r--server/src/vm/vm.lua1334
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