diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2019-11-23 00:05:30 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2019-11-23 00:05:30 +0800 |
commit | 6da2b175e20ed3c03b0dfcfc9046de1e0e5d4444 (patch) | |
tree | fdc22d78150fd1c5edc46732c8b151ccfefb519f /script-beta/test/example/vm.txt | |
parent | d0ff66c9abe9d6abbca12fd811e0c3cb69c1033a (diff) | |
download | lua-language-server-6da2b175e20ed3c03b0dfcfc9046de1e0e5d4444.zip |
正路目录
Diffstat (limited to 'script-beta/test/example/vm.txt')
-rw-r--r-- | script-beta/test/example/vm.txt | 1544 |
1 files changed, 0 insertions, 1544 deletions
diff --git a/script-beta/test/example/vm.txt b/script-beta/test/example/vm.txt deleted file mode 100644 index f2f4144d..00000000 --- a/script-beta/test/example/vm.txt +++ /dev/null @@ -1,1544 +0,0 @@ -local env = require 'core.env' -local library = require 'core.library' -local createValue = require 'core.value' - -local DefaultSource = { start = 0, finish = 0 } -local GlobalChild - --- 根据赋值顺序决定遍历顺序的表 -local function orderTable() - local t = {} - local list = {} - local mark = {} - return setmetatable(t, { - __newindex = function (self, k, v) - if not mark[k] then - mark[k] = true - list[#list+1] = k - end - rawset(self, k, v) - end, - __pairs = function (self) - local i = 0 - return function () - while true do - i = i + 1 - local k = list[i] - if not k then - return nil, nil - end - local v = t[k] - if v ~= nil then - return k, v - end - end - end - end, - }) -end - -local function readOnly(t) - return setmetatable({}, { - __index = function (self, k) - if k == nil then - return nil - end - local v = t[k] - if type(v) == 'table' then - v = readOnly(v) - end - self[k] = v - return v - end, - __len = function (self) - return #t - end, - __pairs = function (self) - local keys = {} - local mark = {} - for k in next, self do - keys[#keys+1] = k - end - for k in pairs(t) do - if not mark[k] then - mark[k] = true - keys[#keys+1] = k - end - end - local i = 0 - return function () - i = i + 1 - local k = keys[i] - return k, self[k] - end - end, - __source = t, - }) -end - -local mt = {} -mt.__index = mt - -function mt:createDummyVar(source, value) - local loc = { - type = 'local', - key = '', - source = source or DefaultSource, - } - self:setValue(loc, value, source) - return loc -end - -function mt:createLocal(key, source, value) - local loc = { - type = 'local', - key = key, - source = source or DefaultSource, - close = self.scope.block.finish, - } - - if source then - source.isLocal = true - end - - local shadow = self.scope.locals[key] - if shadow then - shadow.close = source and (source.start-1) - 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 - - self:addInfo(loc, 'local', source) - self:setValue(loc, value, source) - return loc -end - -function mt:createArg(key, source, value) - local loc = self:createLocal(key, source, value) - if source then - source.isArg = true - end - return loc -end - -function mt:scopePush(block) - if not block.start then - error('Scope push without start!') - end - self.scope:push() - self.scope.block = block -end - -function mt:scopePop() - self.scope:pop() -end - -function mt:addInfo(obj, type, source) - if source and not source.start then - error('Miss start: ' .. table.dump(source)) - end - obj[#obj+1] = { - type = type, - source = source or DefaultSource, - } - if source then - source.uri = self.uri - local other = self.results.sources[source] - if other then - if other.type == 'multi-source' then - other[#other+1] = obj - else - other = { - type = 'multi-source', - [1] = other, - [2] = obj, - } - end - else - self.results.sources[source] = obj - end - if type == 'set' or type == 'return' then - if not obj.declarat then - obj.declarat = source - end - end - end - return obj -end - -function mt:createDots(index, source) - local dots = { - type = 'dots', - source = source or DefaultSource, - func = self:getCurrentFunction(), - index = index, - } - self.chunk.dots = dots - return dots -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 - if obj.type == 'pair' then - local value = self:getExp(obj[2]) - local key = obj[1] - if key.index then - local index = self:getIndex(key) - local field = self:createField(tbl, index, key) - if value.type == 'list' then - self:setValue(field, value[1], key) - else - self:setValue(field, value, key) - end - else - if key.type == 'name' then - local field = self:createField(tbl, key[1], key) - self.results.indexs[#self.results.indexs+1] = field - key.isIndex = true - if value.type == 'list' then - self:setValue(field, value[1], key) - else - self:setValue(field, value, key) - end - end - end - else - local value = self:getExp(obj) - if value.type == 'list' then - if index == #source then - for i, v in ipairs(value) do - local field = self:createField(tbl, n + i) - self:setValue(field, v) - end - else - n = n + 1 - local field = self:createField(tbl, n) - self:setValue(field, value[1]) - end - else - n = n + 1 - local field = self:createField(tbl, n) - self:setValue(field, value) - end - -- 处理写了一半的 key = value,把name类的数组元素视为哈希键 - if obj.type == 'name' then - obj.isIndex = true - end - end - end - return tbl -end - -function mt:mergeValue(a, b, mark) - if a == b then - return - end - if not mark then - mark = {} - end - if mark[a] or mark[b] then - return - end - if a.uri ~= self.uri then - return - end - mark[a] = true - mark[b] = true - self:mergeChild(a, b, mark) - for k in pairs(a) do - a[k] = nil - end - for k, v in pairs(b) do - a[k] = v - end -end - -function mt:mergeField(a, b, mark) - if a == b then - return - end - if not mark then - mark = {} - end - for i, info in ipairs(a) do - a[i] = nil - b[#b+1] = info - end - for i, v in ipairs(b) do - a[i] = v - end - self:mergeValue(a.value, b.value, mark) -end - -function mt:mergeChild(a, b, mark) - if a == b then - return - end - if not a.child and not b.child then - return - end - if not mark then - mark = {} - end - if a.uri ~= self.uri then - return - end - if b.uri == self.uri then - local child = a.child or orderTable() - local other = b.child or orderTable() - a.child = nil - b.child = nil - for k, v in pairs(other) do - if child[k] then - self:mergeField(child[k], v, mark) - else - child[k] = v - end - end - a.child = child - b.child = child - else - local child = a.child or orderTable() - local other = b.child - if not other then - return - end - a.child = nil - for k, v in pairs(other) do - child[k] = v - end - a.child = child - end -end - -function mt:setValue(var, value, source) - if value and value.type == 'list' then - error('Cant set value list') - end - value = value or self:createValue('any', source) - if source and source.start then - self:addInfo(var, 'set', source) - self:addInfo(value, 'set', source) - end - if var.value then - if value.type == 'any' then - self:mergeChild(var.value, value) - elseif value.type == 'nil' then - self:mergeValue(var.value, value) - elseif var.value.uri == self.uri then - var.value = value - end - value = var.value - else - var.value = value - end - return value -end - -function mt:getValue(var) - if not var.value then - var.value = self:createValue('any') - end - return var.value -end - -function mt:createField(pValue, name, source) - if pValue.type == 'local' or pValue.type == 'field' then - error('Only value can create field') - end - local field = { - type = 'field', - key = name, - source = source or DefaultSource, - } - - if not pValue.child then - pValue.child = orderTable() - end - pValue.child[name] = field - self:inference(pValue, 'table') - return field -end - -function mt:getField(pValue, name, source) - local field = (pValue.child and pValue.child[name]) - if not field and pValue.ENV then - if self.lsp then - field = self.lsp:getGlobal(name) - end - end - if not field then - field = self:createField(pValue, name, source) - end - return field -end - -function mt:isGlobal(field) - if field.type ~= 'field' then - return false - end - if field.parent.value.ENV then - return true - else - return false - end -end - -function mt:buildFunction(exp, object) - local func = self:createValue('function', exp) - func.args = {} - func.argValues = {} - - if not exp then - return func - end - - self:scopePush(exp) - self.chunk:push() - self.chunk:cut 'dots' - self.chunk:cut 'labels' - self.chunk.func = func - - if object then - local var = self:createArg('self', object.source, self:getValue(object)) - var.hide = true - func.args[1] = var - end - - local stop - self:forList(exp.arg, function (arg) - if stop then - return - end - if arg.type == 'name' then - local var = self:createArg(arg[1], arg) - arg.isArg = true - func.args[#func.args+1] = var - func.argValues[#func.args] = self:getValue(var) - elseif arg.type == '...' then - self:createDots(#func.args+1, arg) - for _ = 1, 10 do - func.argValues[#func.argValues+1] = self:createValue('any', arg) - end - stop = true - end - end) - - self:doActions(exp) - - self.results.funcs[#self.results.funcs+1] = func - - self.chunk:pop() - self:scopePop() - - return func -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:countList(list) - if not list then - return 0 - end - if list.type == 'list' then - return #list - end - return 1 -end - -function mt:updateFunctionArgs(func) - if not func.argValues then - return - end - if not func.args then - return - end - - local values = func.argValues - for i, var in ipairs(func.args) do - if var.type == 'dots' then - local list = { - type = 'list', - } - for n = i, #values do - list[n-i+1] = values[n] - end - self:setValue(var, list) - break - else - self:setValue(var, values[i]) - end - end -end - -function mt:setFunctionArg(func, values) - if func.uri ~= self.uri then - return - end - if not func.argValues then - func.argValues = {} - end - for i = 1, #values do - if not func.argValues[i] then - func.argValues[i] = values[i] - end - self:inference(values[i], func.argValues[i].type) - self:inference(func.argValues[i], values[i].type) - end - - self:updateFunctionArgs(func) -end - -function mt:getFunctionArg(func, i) - if not func.argValues then - func.argValues = {} - end - if not func.argValues[i] then - for n = #func.argValues+1, i do - func.argValues[n] = self:createValue('any') - end - end - return func.argValues[i] -end - -function mt:checkMetaIndex(value, meta) - local index = self:getField(meta, '__index') - if not index then - return - end - local indexValue = self:getValue(index) - -- TODO 支持function - self:mergeChild(value, indexValue) -end - -function mt:callSetMetaTable(func, values) - if not values[1] then - values[1] = self:createValue('any') - end - if not values[2] then - values[2] = self:createValue('any') - end - self:setFunctionReturn(func, 1, values[1]) - - values[1].metatable = values[2] - -- 检查 __index - self:checkMetaIndex(values[1], values[2]) -end - -function mt:getRequire(strValue, destVM) - -- 取出对方的主函数 - local main = destVM.results.main - -- 获取主函数返回值,注意不能修改对方的环境 - local mainValue - if main.returns then - mainValue = readOnly(main.returns[1]) - else - mainValue = self:createValue('boolean', nil, true) - mainValue.uri = destVM.uri - end - - return mainValue -end - -function mt:getLoadFile(strValue, destVM) - -- 取出对方的主函数 - local main = destVM.results.main - -- loadfile 的返回值就是对方的主函数 - local mainValue = readOnly(main) - - return mainValue -end - -function mt:tryRequireOne(strValue, mode) - if not self.lsp or not self.lsp.workspace then - return nil - end - local str = strValue.value - if type(str) == 'string' then - -- 支持 require 'xxx' 的转到定义 - local strSource = strValue.source - self.results.sources[strSource] = strValue - strValue.isRequire = true - - local uri - if mode == 'require' then - uri = self.lsp.workspace:searchPath(self.uri, str) - elseif mode == 'loadfile' then - uri = self.lsp.workspace:loadPath(self.uri, str) - elseif mode == 'dofile' then - uri = self.lsp.workspace:loadPath(self.uri, str) - end - if not uri then - return nil - end - - strValue.uri = uri - -- 如果取不到VM(不编译),则做个标记,之后再取一次 - local destVM = self.lsp:getVM(uri) - self.lsp:compileChain(self.uri, uri) - if destVM then - if mode == 'require' then - return self:getRequire(strValue, destVM) - elseif mode == 'loadfile' then - return self:getLoadFile(strValue, destVM) - elseif mode == 'dofile' then - return self:getRequire(strValue, destVM) - end - end - end - return nil -end - -function mt:callRequire(func, values) - if not values[1] then - values[1] = self:createValue('any') - end - local str = values[1].value - if type(str) ~= 'string' then - return - end - local lib = library.library[str] - if lib then - local value = self:getLibValue(lib, 'library') - self:setFunctionReturn(func, 1, value) - return - else - local requireValue = self:tryRequireOne(values[1], 'require') - if not requireValue then - requireValue = self:createValue('boolean') - requireValue.isRequire = true - end - self:setFunctionReturn(func, 1, requireValue) - end -end - -function mt:callLoadFile(func, values) - if not values[1] then - values[1] = self:createValue('any') - end - local str = values[1].value - if type(str) ~= 'string' then - return - end - local requireValue = self:tryRequireOne(values[1], 'loadfile') - if not requireValue then - requireValue = self:createValue('any') - requireValue.isRequire = true - end - self:setFunctionReturn(func, 1, requireValue) -end - -function mt:callDoFile(func, values) - if not values[1] then - values[1] = self:createValue('any') - end - local str = values[1].value - if type(str) ~= 'string' then - return - end - local requireValue = self:tryRequireOne(values[1], 'dofile') - if not requireValue then - requireValue = self:createValue('any') - requireValue.isRequire = true - end - self:setFunctionReturn(func, 1, requireValue) -end - -function mt:call(func, values) - self:inference(func, 'function') - local lib = func.lib - if lib then - if lib.args then - for i, arg in ipairs(lib.args) do - if arg.type == '...' then - self:inference(self:getFunctionArg(func, i), 'any') - else - self:inference(self:getFunctionArg(func, i), arg.type or 'any') - end - end - end - if lib.returns then - for i, rtn in ipairs(lib.returns) do - if rtn.type == '...' then - self:inference(self:getFunctionReturns(func, i), 'any') - else - self:inference(self:getFunctionReturns(func, i), rtn.type or 'any') - end - end - end - if lib.special then - if lib.special == 'setmetatable' then - self:callSetMetaTable(func, values) - 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) - end - end - end - - self:setFunctionArg(func, values) - - return self:getFunctionReturns(func) -end - -function mt:getCurrentFunction() - return self.chunk.func -end - -function mt:mergeFunctionReturn(func, index, value) - if not func.returns[index] then - func.returns[index] = value - return - end - if value.type == 'nil' then - return - end - if value == 'any' and func.returns[index] ~= 'nil' then - return - end - func.returns[index] = value -end - -function mt:setFunctionReturn(func, index, value) - func:set('hasReturn', true) - if not func.returns then - func.returns = { - type = 'list', - } - end - if value then - if value.type == 'list' then - for i, v in ipairs(value) do - self:mergeFunctionReturn(func, index+i-1, v) - end - else - self:mergeFunctionReturn(func, index, value) - end - else - self:mergeFunctionReturn(func, index, self:createValue('any')) - end -end - -function mt:getFunctionReturns(func, i) - if func.maxReturns and i and func.maxReturns < i then - return self:createValue('nil') - end - if not func.returns then - func.returns = { - type = 'list', - } - end - if i then - if not func.returns[i] then - for n = #func.returns+1, i do - func.returns[n] = self:createValue('any') - end - end - return func.returns[i] - else - return func.returns - end -end - -function mt:inference(value, type) - if type == '...' then - error('Value type cant be ...') - end - if value.type == 'any' and type ~= 'nil' then - value.type = type - end -end - -function mt:createValue(tp, source, v) - local value = createValue(tp, self.uri, source, v) - local lib = library.object[tp] - if lib then - self:getLibChild(value, lib, 'object') - end - return value -end - -function mt:getLibChild(value, lib, parentType) - if lib.child then - if self.libraryChild[lib] then - value.child = self.libraryChild[lib] - return - end - self.libraryChild[lib] = {} - 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 - if value.child then - for k, v in pairs(value.child) do - self.libraryChild[lib][k] = v - end - end - value.child = self.libraryChild[lib] - end -end - -function mt:getLibValue(lib, parentType, v) - if self.libraryValue[lib] then - return self.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 - self:setFunctionArg(value, values) - 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 - self.libraryValue[lib] = value - value.lib = lib - value.parentType = parentType - - self:getLibChild(value, lib, parentType) - - return value -end - -function mt:getName(name, source) - local loc = self.scope.locals[name] - if loc then - return loc - end - local ENV = self.scope.locals._ENV - local global = self:getField(self:getValue(ENV), name, source) - global.parent = ENV - return global -end - -function mt:getIndex(obj) - local tp = obj.type - if tp == 'name' then - local var = self:getName(obj[1]) - local value = self:getValue(var) - self:addInfo(var, 'get', obj) - return value - elseif (tp == 'string' or tp == 'number' or tp == 'boolean') then - return obj[1] - else - return self:getExp(obj) - end -end - --- expect表示遇到 ... 时,期待的返回数量 -function mt:unpackDots(res, expect) - local dots = self:getDots(1) - local func = dots.func - local start = dots.index - if expect then - local finish = start + expect - 1 - for i = start, finish do - res[#res+1] = self:getFunctionArg(func, i) - end - else - if not func.argValues then - return - end - for i = start, #func.argValues do - res[#res+1] = func.argValues[i] - end - end -end - -function mt:unpackList(list, expect) - local res = { - type = 'list', - } - if not list then - return res - end - if list.type == 'list' or list.type == 'call' then - for i, exp in ipairs(list) do - if exp.type == '...' then - self:unpackDots(res, expect) - break - end - local value = self:getExp(exp) - if value.type == 'list' then - if i == #list then - for _, v in ipairs(value) do - res[#res+1] = v - end - else - res[#res+1] = value[1] - end - else - res[#res+1] = value - end - end - elseif list.type == '...' then - self:unpackDots(res, expect) - else - local value = self:getExp(list) - if value.type == 'list' then - for i, v in ipairs(value) do - res[i] = v - end - else - res[1] = value - end - end - for _, v in ipairs(res) do - if v.type == 'list' then - error('Unpack list') - end - end - return res -end - -function mt:getSimple(simple, mode) - local value = self:getExp(simple[1]) - local field - local parentName - local tp = simple[1].type - if tp == 'name' then - field = self:getName(simple[1][1]) - parentName = field.key - elseif tp == 'string' or tp == 'number' or tp == 'nil' or tp == 'boolean' then - local v = self:createValue(tp, simple[1], simple[1][1]) - field = self:createDummyVar(simple[1], v) - parentName = '*' .. tp - else - local v = self:createValue('any', simple[1]) - field = self:createDummyVar(simple[1], v) - parentName = '?' - end - local object - local lastField = field - for i = 2, #simple do - local obj = simple[i] - local tp = obj.type - - if tp == 'call' then - local args = self:unpackList(obj) - if object then - table.insert(args, 1, self:getValue(object)) - end - local func = value - -- 函数的返回值一定是list - value = self:call(func, args) - if i < #simple then - value = value[1] or self:createValue('any') - end - self.results.calls[#self.results.calls+1] = { - args = obj, - lastObj = simple[i-1], - nextObj = simple[i+1], - func = func, - } - parentName = parentName .. '(...)' - elseif tp == 'index' then - local child = obj[1] - local index = self:getIndex(child) - field = self:getField(value, index, child) - field.parentValue = value - value = self:getValue(field) - if mode == 'value' or i < #simple then - self:addInfo(field, 'get', obj) - end - field.parent = lastField - lastField = field - obj.object = object - obj.parentName = parentName - if obj[1].type == 'string' then - parentName = ('%s[%q]'):format(parentName, index) - elseif obj[1].type == 'number' or obj[1].type == 'boolean' then - parentName = ('%s[%s]'):format(parentName, index) - else - parentName = ('%s[?]'):format(parentName) - end - elseif tp == 'name' then - field = self:getField(value, obj[1], obj) - field.parentValue = value - value = self:getValue(field) - if mode == 'value' or i < #simple then - self:addInfo(field, 'get', obj) - end - field.parent = lastField - lastField = field - obj.object = object - obj.parentName = parentName - parentName = parentName .. '.' .. field.key - elseif tp == ':' then - object = field - simple[i-1].colon = obj - elseif tp == '.' then - simple[i-1].dot = obj - end - end - if mode == 'value' then - return value, object - elseif mode == 'field' then - return field, object - end - error('Unknow simple mode: ' .. mode) -end - -function mt:isTrue(v) - if v.type == 'nil' then - return false - end - if v.type == 'boolean' and not v.value then - return false - end - return true -end - -function mt:getBinary(exp) - local v1 = self:getExp(exp[1]) - local v2 = self:getExp(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 - self:inference(v1, 'number') - self:inference(v2, 'number') - return self:createValue('boolean') - elseif op == '~=' - or op == '==' - then - return self:createValue('boolean') - elseif op == '|' - or op == '~' - or op == '&' - or op == '<<' - or op == '>>' - then - self:inference(v1, 'integer') - self:inference(v2, 'integer') - if math.type(v1.value) == 'integer' and math.type(v2.value) == 'integer' then - if op == '|' then - return self:createValue('integer', v1.value | v2.value) - elseif op == '~' then - return self:createValue('integer', v1.value ~ v2.value) - elseif op == '&' then - return self:createValue('integer', v1.value &v2.value) - elseif op == '<<' then - return self:createValue('integer', v1.value << v2.value) - elseif op == '>>' then - return self:createValue('integer', v1.value >> v2.value) - end - end - return self:createValue('integer') - elseif op == '..' then - self:inference(v1, 'string') - self:inference(v2, 'string') - if type(v1.value) == 'string' and type(v2.value) == 'string' then - return self:createValue('string', nil, v1.value .. v2.value) - end - return self:createValue('string') - elseif op == '+' - or op == '-' - or op == '*' - or op == '/' - or op == '^' - or op == '%' - or op == '//' - then - self:inference(v1, 'number') - self:inference(v2, 'number') - if type(v1.value) == 'number' and type(v2.value) == 'number' then - if op == '+' then - return self:createValue('number', nil, v1.value + v2.value) - elseif op == '-' then - return self:createValue('number', nil, v1.value - v2.value) - elseif op == '*' then - return self:createValue('number', nil, v1.value * v2.value) - elseif op == '/' then - if v2.value ~= 0 then - return self:createValue('number', nil, v1.value / v2.value) - end - elseif op == '^' then - return self:createValue('number', nil, v1.value ^ v2.value) - elseif op == '%' then - if v2.value ~= 0 then - return self:createValue('number', nil, v1.value % v2.value) - end - elseif op == '//' then - if v2.value ~= 0 then - return self:createValue('number', nil, v1.value // v2.value) - end - end - end - return self:createValue('number') - end - return nil -end - -function mt:getUnary(exp) - local v1 = self:getExp(exp[1]) - local op = exp.op - -- TODO 搜索元方法 - if op == 'not' then - return self:createValue('boolean') - elseif op == '#' then - self:inference(v1, 'table') - if type(v1.value) == 'string' then - return self:createValue('integer', nil, #v1.value) - end - return self:createValue('integer') - elseif op == '-' then - self:inference(v1, 'number') - if type(v1.value) == 'number' then - return self:createValue('number', nil, -v1.value) - end - return self:createValue('number') - elseif op == '~' then - self:inference(v1, 'integer') - if math.type(v1.value) == 'integer' then - return self:createValue('integer', nil, ~v1.value) - end - return self:createValue('integer') - end - return nil -end - -function mt:getDots() - if not self.chunk.dots then - self:createDots(1) - end - return self.chunk.dots -end - -function mt:getExp(exp) - local tp = exp.type - if tp == 'nil' then - return self:createValue('nil', exp) - elseif tp == 'string' then - self.results.strings[#self.results.strings+1] = exp - 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 var = self:getName(exp[1], exp) - local value = self:getValue(var) - self:addInfo(var, 'get', exp) - return value - elseif tp == 'simple' then - return self:getSimple(exp, 'value') - 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 - local value = { type = 'list' } - self:unpackDots(value) - return value - end - error('Unkown exp type: ' .. tostring(tp)) -end - -function mt:doDo(action) - self:scopePush(action) - self:doActions(action) - self:scopePop() -end - -function mt:doReturn(action) - self:getCurrentFunction():set('hasReturn', true) - for i, exp in ipairs(action) do - local value = self:getExp(exp) - if value.type == 'list' then - if i == #action then - if #value == 0 then - value[1] = self:createValue('any', exp) - end - for x, v in ipairs(value) do - self:addInfo(v, 'return', exp) - self:setFunctionReturn(self:getCurrentFunction(), i + x - 1, v) - end - break - else - local v = value[1] or self:createValue('nil', exp) - self:addInfo(v, 'return', exp) - self:setFunctionReturn(self:getCurrentFunction(), i, v) - end - else - self:addInfo(value, 'return', exp) - self:setFunctionReturn(self:getCurrentFunction(), i, value) - end - end -end - -function mt:createLabel(action) - local name = action[1] - if not self.chunk.labels[name] then - local label = { - type = 'label', - key = name, - } - self.chunk.labels[name] = label - self.results.labels[#self.results.labels+1] = label - end - return self.chunk.labels[name] -end - -function mt:doSet(action) - if not action[2] then - return - end - local n = self:countList(action[1]) - -- 要先计算值 - local values = self:unpackList(action[2], n) - self:forList(action[1], function (key) - local value = table.remove(values, 1) - if key.type == 'name' then - local var = self:getName(key[1], key) - self:setValue(var, value, key) - if self:isGlobal(var) then - self.results.globals[#self.results.globals+1] = { - type = 'global', - global = var, - } - end - elseif key.type == 'simple' then - local field = self:getSimple(key, 'field') - self:setValue(field, value, key[#key]) - local var = field - repeat - if self:isGlobal(var) then - self.results.globals[#self.results.globals+1] = { - type = 'field', - global = var, - } - break - end - var = var.parent - until not var - end - end) -end - -function mt:doLocal(action) - local n = self:countList(action[1]) - local values - if action[2] then - values = self:unpackList(action[2], n) - end - self:forList(action[1], function (key) - local value - if values then - value = table.remove(values, 1) - end - self:createLocal(key[1], key, value) - end) -end - -function mt:doIf(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) - - local min = self:unpackList(action.min)[1] - 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 args = self:unpackList(action.exp) - - self:scopePush(action) - local func = table.remove(args, 1) or self:createValue('any') - local values = self:call(func, args) - self:forList(action.arg, function (arg) - local value = table.remove(values, 1) - self:createLocal(arg[1], arg, value) - end) - - self:doActions(action) - - self:scopePop() -end - -function mt:doWhile(action) - - self:getExp(action.filter) - - self:scopePush(action) - self:doActions(action) - self:scopePop() -end - -function mt:doRepeat(action) - self:scopePush(action) - self:doActions(action) - self:getExp(action.filter) - self:scopePop() -end - -function mt:doFunction(action) - local name = action.name - local var, object - local source - if name then - if name.type == 'simple' then - var, object = self:getSimple(name, 'field') - source = name[#name] - else - var = self:getName(name[1], name) - source = name - end - end - local func = self:buildFunction(action, object) - if var then - self:setValue(var, func, source) - end -end - -function mt:doLocalFunction(action) - local name = action.name - local var, object - local source - if name then - if name.type == 'simple' then - var, object = self:getSimple(name, 'field') - source = name[#name] - else - var = self:createLocal(name[1], name) - source = name - end - end - local func = self:buildFunction(action, object) - if var then - self:setValue(var, func, source) - end -end - -function mt:doAction(action) - if not action then - -- Skip - return - end - local tp = action.type - if tp == 'do' then - self:doDo(action) - elseif tp == 'break' then - elseif tp == 'return' then - self:doReturn(action) - elseif tp == 'label' then - local label = self:createLabel(action) - self:addInfo(label, 'set', action) - elseif tp == 'goto' then - local label = self:createLabel(action) - self:addInfo(label, 'goto', action) - elseif tp == 'set' then - self:doSet(action) - elseif tp == 'local' then - self:doLocal(action) - elseif tp == 'simple' then - -- call - self:getSimple(action, 'value') - 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) - end -end - -function mt:doActions(actions) - for _, action in ipairs(actions) do - self:doAction(action) - if coroutine.isyieldable() then - coroutine.yield() - end - end -end - -function mt:createEnvironment() - self.scope.block = { start = 0, finish = math.maxinteger } - -- 整个文件是一个函数 - self.chunk.func = self:buildFunction() - self.results.main = self.chunk.func - -- 隐藏的上值`_ENV` - local parent = self:createLocal('_ENV') - parent.hide = true - local envValue = self:setValue(parent, self:buildTable()) - -- _ENV 有个特殊标记 - envValue.ENV = true - -- 隐藏的参数`...` - self:createDots(1) - - -- 设置全局变量 - if not GlobalChild then - for name, lib in pairs(library.global) do - local field = self:createField(envValue, name) - local value = self:getLibValue(lib, 'global') - value = self:setValue(field, value) - end - GlobalChild = envValue.child - end - envValue.child = readOnly(GlobalChild) - - -- 设置 _G 使用 _ENV 的child - local g = self:getField(envValue, '_G') - local gValue = self:getValue(g) - gValue.child = envValue.child - self.env = envValue -end - -local function compile(ast, lsp, uri) - local vm = setmetatable({ - scope = env { - locals = {}, - }, - chunk = env { - labels = {}, - }, - results = { - locals = {}, - labels = {}, - funcs = {}, - calls = {}, - sources= {}, - strings= {}, - indexs = {}, - globals= {}, - main = nil, - }, - libraryValue = {}, - libraryChild = {}, - lsp = lsp, - uri = uri, - }, mt) - - -- 创建初始环境 - vm:createEnvironment() - - -- 执行代码 - vm:doActions(ast) - - vm.scope = nil - vm.chunk = nil - vm.libraryValue = nil - vm.libraryChild = nil - - return vm -end - -return function (ast, lsp, uri) - if not ast then - return nil - end - local suc, res = xpcall(compile, log.error, ast, lsp, uri) - if not suc then - return nil - end - return res -end |