diff options
-rw-r--r-- | server/src/core/init.lua | 1 | ||||
-rw-r--r-- | server/src/vm/dots.lua | 6 | ||||
-rw-r--r-- | server/src/vm/env.lua (renamed from server/src/core/env.lua) | 0 | ||||
-rw-r--r-- | server/src/vm/function.lua | 36 | ||||
-rw-r--r-- | server/src/vm/global.lua | 20 | ||||
-rw-r--r-- | server/src/vm/init.lua | 1 | ||||
-rw-r--r-- | server/src/vm/library.lua | 63 | ||||
-rw-r--r-- | server/src/vm/local.lua (renamed from server/src/core/local.lua) | 17 | ||||
-rw-r--r-- | server/src/vm/source.lua | 18 | ||||
-rw-r--r-- | server/src/vm/value.lua (renamed from server/src/core/value.lua) | 28 | ||||
-rw-r--r-- | server/src/vm/vm.lua (renamed from server/src/core/vm.lua) | 249 | ||||
-rw-r--r-- | server/src/vm/vm.txt (renamed from server/src/core/vm.txt) | 0 |
12 files changed, 260 insertions, 179 deletions
diff --git a/server/src/core/init.lua b/server/src/core/init.lua index 68898814..148871a1 100644 --- a/server/src/core/init.lua +++ b/server/src/core/init.lua @@ -11,7 +11,6 @@ local api = { signature = require 'core.signature', documentSymbol = require 'core.document_symbol', global = require 'core.global', - vm = require 'core.vm', } return api diff --git a/server/src/vm/dots.lua b/server/src/vm/dots.lua new file mode 100644 index 00000000..1736de5c --- /dev/null +++ b/server/src/vm/dots.lua @@ -0,0 +1,6 @@ +local mt = {} +mt.__index = mt +mt.type = 'dots' + +return function () +end diff --git a/server/src/core/env.lua b/server/src/vm/env.lua index ada26145..ada26145 100644 --- a/server/src/core/env.lua +++ b/server/src/vm/env.lua diff --git a/server/src/vm/function.lua b/server/src/vm/function.lua new file mode 100644 index 00000000..25465398 --- /dev/null +++ b/server/src/vm/function.lua @@ -0,0 +1,36 @@ +local env = require 'vm.env' +local createDots = require 'vm.dots' + +local mt = {} +mt.__index = mt +mt.type = 'function' +mt._returnDots = false + +function mt:getUri() + return self.source.uri +end + +function mt:saveLocal(name, loc) + self.locals[name] = loc +end + +function mt:setReturn(index, value) + self.returns[index] = value +end + +function mt:returnDots(index, value) + self.returns[index] = value + self._returnDots = true +end + +return function (source) + if not source then + error('Function must has a source') + end + local self = setmetatable({ + source = source, + locals = {}, + returns = {}, + }, mt) + return self +end diff --git a/server/src/vm/global.lua b/server/src/vm/global.lua new file mode 100644 index 00000000..4e368641 --- /dev/null +++ b/server/src/vm/global.lua @@ -0,0 +1,20 @@ +local createValue = require 'vm.value' +local library = require 'core.library' +local libraryBuilder = require 'vm.library' + +return function (lsp) + local global = lsp and lsp.globalValue + if not global then + global = createValue('table') + end + for name, lib in pairs(library.global) do + if not global:rawGet(name) then + local value = libraryBuilder.value(lib) + global:rawSet(name, value) + 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 new file mode 100644 index 00000000..87576ba5 --- /dev/null +++ b/server/src/vm/init.lua @@ -0,0 +1 @@ +return require 'vm.vm' diff --git a/server/src/vm/library.lua b/server/src/vm/library.lua new file mode 100644 index 00000000..a6b9629e --- /dev/null +++ b/server/src/vm/library.lua @@ -0,0 +1,63 @@ +local createValue = require 'vm.value' +local createFunction = require 'vm.function' + +local buildLibValue +local buildLibChild + +local function getDefaultSource() + return { + start = 0, + finish = 0, + uri = '', + } +end + +function buildLibValue(lib) + local tp = lib.type + local value + if tp == 'table' then + value = createValue('table') + elseif tp == 'function' then + value = createValue('function') + local func = createFunction(getDefaultSource()) + value:setFunction(func) + if lib.returns then + for i, rtn in ipairs(lib.returns) do + if rtn.type == '...' then + func:returnDots(i, buildLibValue(rtn)) + else + func:setReturn(i, buildLibValue(rtn)) + end + end + end + elseif tp == 'string' then + value = createValue('string') + elseif tp == 'boolean' then + value = createValue('boolean') + elseif tp == 'number' then + value = createValue('number') + elseif tp == 'integer' then + value = createValue('integer') + elseif tp == 'nil' then + value = createValue('nil') + elseif tp == '...' then + value = createValue('any') + else + value = createValue(tp or 'any') + end + value:setLib(lib) + + if lib.child then + for fName, fLib in pairs(lib.child) do + local fValue = buildLibValue(fLib) + value:rawSet(fName, fValue) + end + end + + return value +end + +return { + value = buildLibValue, + child = buildLibChild, +} diff --git a/server/src/core/local.lua b/server/src/vm/local.lua index 7deac275..f1c33ecf 100644 --- a/server/src/core/local.lua +++ b/server/src/vm/local.lua @@ -35,7 +35,24 @@ function mt:eachInfo(callback) end end +function mt:setFlag(name, v) + if not self._flag then + self._flag = {} + end + self._flag[name] = v +end + +function mt:getFlag(name) + if not self._flag then + return nil + end + return self._flag[name] +end + return function (name, source, value) + if not value then + error('Local must has a value') + end local self = setmetatable({ name = name, source = source or getDefaultSource(), diff --git a/server/src/vm/source.lua b/server/src/vm/source.lua new file mode 100644 index 00000000..5ec602c6 --- /dev/null +++ b/server/src/vm/source.lua @@ -0,0 +1,18 @@ +local mt = {} +mt.__index = mt + +function mt:bindLocal(loc) + if loc then + self._bindLocal = loc + else + return self._bindLocal + end +end + +function mt:setUri(uri) + self._uri = uri +end + +return function (source) + return setmetatable(source, mt) +end diff --git a/server/src/core/value.lua b/server/src/vm/value.lua index fdd9d902..21dd4307 100644 --- a/server/src/core/value.lua +++ b/server/src/vm/value.lua @@ -21,7 +21,7 @@ end function mt:setType(tp, rate) if type(tp) == 'table' then for _, ctp in ipairs(tp) do - self:inference(ctp, rate) + self:setType(ctp, rate) end return end @@ -166,11 +166,17 @@ function mt:mergeValue(value) self._child[k] = v end end + for _, info in ipairs(value) do + self[#self+1] = info + end if value._meta then self._meta = value._meta end - for _, info in ipairs(value) do - self[#self+1] = info + if value._func then + self._func = value._func + end + if value._lib then + self._lib = value._lib end end @@ -194,13 +200,25 @@ function mt:eachInfo(callback) return nil end -return function (tp, source, v) +function mt:setFunction(func) + self._func = func + self:setType('function', 1.0) +end + +function mt:setLib(lib) + self._lib = lib +end + +function mt:getLib() + return self._lib +end + +return function (tp, source) if tp == '...' then error('Value type cant be ...') end local self = setmetatable({ source = source or getDefaultSource(), - _value = v, _type = {}, }, mt) if type(tp) == 'table' then diff --git a/server/src/core/vm.lua b/server/src/vm/vm.lua index 66fdd2c6..48d7e038 100644 --- a/server/src/core/vm.lua +++ b/server/src/vm/vm.lua @@ -1,9 +1,9 @@ -local env = require 'core.env' local library = require 'core.library' -local createValue = require 'core.value' - -local LibraryValue = {} -local LibraryChild = {} +local createValue = require 'vm.value' +local createLocal = require 'vm.local' +local createFunction = require 'vm.function' +local instantSource = require 'vm.source' +local buildGlobal = require 'vm.global' local mt = {} mt.__index = mt @@ -12,7 +12,7 @@ function mt:getDefaultSource() return { start = 0, finish = 0, - uri = self.chunk.func.uri, + uri = self:getUri(), } end @@ -36,54 +36,6 @@ function mt:createDummyVar(source, value) return loc end -function mt:createLocal(key, source, value) - if source and source.bind then - self.scope.locals[key] = source.bind - return source.bind - end - local loc = { - type = 'local', - key = key, - source = source or self:getDefaultSource(), - close = self.scope.block.finish, - } - - if source then - source.bind = loc - self.results.sources[#self.results.sources+1] = source - source.isLocal = true - source.uri = self.chunk.func.uri - end - - local shadow = self.scope.locals[key] - if shadow then - if source then - shadow.close = source.start - 1 - end - local group - if shadow.shadow then - group = shadow.shadow - else - group = { shadow } - shadow.shadow = group - end - group[#group+1] = loc - loc.shadow = group - end - - self.scope.locals[key] = loc - self.results.locals[#self.results.locals+1] = loc - - if source then - self:addInfo(loc, 'local', source, value) - if value then - value:addInfo('local', source) - end - end - self:setValue(loc, value, source) - return loc -end - function mt:createField(value, index, source) if source and source.bind then return source.bind @@ -637,77 +589,6 @@ function mt:createValue(tp, source, v) return value end -function mt:getLibChild(value, lib, parentType) - if lib.child then - if LibraryChild[lib] then - value:setChild(LibraryChild[lib]) - return - end - -- 要先声明缓存,以免死循环 - LibraryChild[lib] = value:getChild() - for fName, fLib in pairs(lib.child) do - local fField = self:createField(value, fName) - local fValue = self:getLibValue(fLib, parentType) - self:setValue(fField, fValue) - end - end -end - -function mt:getLibValue(lib, parentType, v) - if LibraryValue[lib] then - return LibraryValue[lib] - end - local tp = lib.type - local value - if tp == 'table' then - value = self:createValue('table') - elseif tp == 'function' then - value = self:createValue('function') - if lib.returns then - local dots - for i, rtn in ipairs(lib.returns) do - self:setFunctionReturn(value, i, self:getLibValue(rtn, parentType)) - if rtn.type == '...' then - dots = true - end - end - if not dots then - value.maxReturns = #lib.returns - end - else - value.maxReturns = 0 - end - if lib.args then - local values = {} - for i, arg in ipairs(lib.args) do - values[i] = self:getLibValue(arg, parentType) or self:createValue('any') - end - -- TODO 确定参数类型 - end - elseif tp == 'string' then - value = self:createValue('string', nil, v or lib.value) - elseif tp == 'boolean' then - value = self:createValue('boolean', nil, v or lib.value) - elseif tp == 'number' then - value = self:createValue('number', nil, v or lib.value) - elseif tp == 'integer' then - value = self:createValue('integer', nil, v or lib.value) - elseif tp == 'nil' then - value = self:createValue('nil') - elseif tp == '...' then - value = self:createValue('any') - else - value = self:createValue(tp or 'any') - end - LibraryValue[lib] = value - value.lib = lib - value.parentType = parentType - - self:getLibChild(value, lib, parentType) - - return value -end - function mt:getName(name, source) if source and source.bind then return source.bind @@ -1373,68 +1254,90 @@ function mt:doActions(actions) end end -function mt:getGlobalValue() - if self.lsp and self.lsp.globalValue then - return self.lsp.globalValue +function mt:createFunction(source) + local value = createValue('function', source) + local func = createFunction(source) + value:setFunction(func) + if source:getUri() == self.uri then + self.funcs[#self.funcs+1] = func + end + return value +end + +function mt:setCurrentFunction(func) + self.currentFunction = func +end + +function mt:saveLocal(name, loc) + self.currentFunction:saveLocal(name, loc) +end + +function mt:getUri() + return self.currentFunction:getUri() +end + +function mt:instantSource(source) + if instantSource(source) then + self.sources[#self.sources+1] = source + end +end + +function mt:bindLocal(source, loc) + if not source then + return + end + self:instantSource(source) + if loc then + source:bindLocal(loc) + source:setUri(self:getUri()) + else + return source:bindLocal() end - local globalValue = self:createValue('table') - globalValue.GLOBAL = true - for name, lib in pairs(library.global) do - local field = self:createField(globalValue, name) - local value = self:getLibValue(lib, 'global') - self:setValue(field, value) +end + +function mt:createLocal(key, source, value) + local loc = self:bindLocal(source) + if loc then + self:saveLocal(key, loc) + return loc end - if self.lsp then - self.lsp.globalValue = globalValue + + if not value then + value = createValue('nil', self:getDefaultSource()) end - return globalValue + + loc = createLocal(key, source, value) + self:saveLocal(key, loc) + self:bindLocal(source, loc) + return loc end -function mt:createEnvironment() - self.scope.block = { start = 0, finish = math.maxinteger } +function mt:createEnvironment(ast) -- 整个文件是一个函数 - self.chunk.func = self:buildFunction() - self.chunk.func.uri = self.uri - self.results.main = self.chunk.func - -- 隐藏的上值`_ENV` - local evnField = self:createLocal('_ENV') - evnField.hide = true - -- 隐藏的参数`...` - self:createDots(1) + self.main = self:createFunction(ast) + self:setCurrentFunction(self.main) -- 全局变量`_G` - local globalValue = self:getGlobalValue() - -- 使用_G初始化_ENV - self:setValue(evnField, globalValue) - self.env = globalValue + local global = buildGlobal(self.lsp) + -- 隐藏的上值`_ENV` + local env = self:createLocal('_ENV', nil, global) + env:setFlag('hide', true) + self.env = env end local function compile(ast, lsp, uri) local vm = setmetatable({ - scope = env { - locals = {}, - }, - chunk = env { - labels = {}, - }, - results = { - locals = {}, - labels = {}, - funcs = {}, - calls = {}, - strings= {}, - infos = {}, - sources= {}, - main = nil, - }, - lsp = lsp, - uri = uri or '', + strings= {}, + sources= {}, + funcs = {}, + main = nil, + env = nil, + lsp = lsp, + uri = uri or '', }, mt) -- 创建初始环境 - vm:createEnvironment() - - -- 执行代码 - vm:doActions(ast) + ast.uri = vm.uri + vm:createEnvironment(ast) -- 检查所有没有调用过的函数,调用一遍 vm:callLeftFuncions() diff --git a/server/src/core/vm.txt b/server/src/vm/vm.txt index 458a7c81..458a7c81 100644 --- a/server/src/core/vm.txt +++ b/server/src/vm/vm.txt |