From 72cb32854c8c1d8d273fcb24b2235e0e7505b99f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Tue, 12 Feb 2019 15:16:43 +0800 Subject: =?UTF-8?q?=E6=9A=82=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/vm/dots.lua | 20 +++++ server/src/vm/function.lua | 7 ++ server/src/vm/multi.lua | 14 ++++ server/src/vm/vm.lua | 201 ++++++++++++++++++++++++--------------------- 4 files changed, 150 insertions(+), 92 deletions(-) (limited to 'server/src/vm') diff --git a/server/src/vm/dots.lua b/server/src/vm/dots.lua index db8e134e..e9a1ac15 100644 --- a/server/src/vm/dots.lua +++ b/server/src/vm/dots.lua @@ -1,7 +1,27 @@ +local createValue = require 'vm.value' + local mt = {} mt.__index = mt mt.type = 'dots' +function mt:set(n, value) + self[n] = value +end + +function mt:get(expect) + local result = {} + if expect then + for i = 1, expect do + result[i] = self[i] or createValue('any') + end + else + for i = 1, #self do + result[i] = self[i] + end + end + return result +end + return function () local self = setmetatable({}, mt) return self diff --git a/server/src/vm/function.lua b/server/src/vm/function.lua index 0d9c4489..4136a5f6 100644 --- a/server/src/vm/function.lua +++ b/server/src/vm/function.lua @@ -85,6 +85,13 @@ function mt:returnDots(index) self.returns[index] = createDots() end +function mt:loadDots(expect) + if not self._dots then + self._dots = createDots() + end + return self._dots:get(expect) +end + function mt:hasRuned() return self._runed > 0 end diff --git a/server/src/vm/multi.lua b/server/src/vm/multi.lua index 91ab4577..ffaae1c0 100644 --- a/server/src/vm/multi.lua +++ b/server/src/vm/multi.lua @@ -8,6 +8,20 @@ function mt:push(value) self[#self+1] = value end +function mt:get(index) + for n = #self+1, index do + self[n] = createValue('any') + end + return self[index] +end + +function mt:set(index, value) + for n = #self+1, index-1 do + self[n] = createValue('any') + end + self[index] = value +end + function mt:first() local value = self[1] if not value then diff --git a/server/src/vm/vm.lua b/server/src/vm/vm.lua index a988adb8..7a95b722 100644 --- a/server/src/vm/vm.lua +++ b/server/src/vm/vm.lua @@ -258,6 +258,12 @@ function mt:setFunctionArg(func, values) for i = 1, #values do func.argValues[i] = values[i] end + if func.dots then + local dotsIndex = #func.args + for i = dotsIndex, #values do + func.dots:set(i - dotsIndex + 1, values[i]) + end + end end function mt:getFunctionArg(func, i) @@ -399,23 +405,22 @@ function mt:callDoFile(func, values) end function mt:call(func, values, source) - func:inference('function', 0.9) local lib = func.lib if lib then if lib.args then for i, arg in ipairs(lib.args) do local value = values[i] if value and arg.type ~= '...' then - value:inference(arg.type, 1.0) + value:setType(arg.type, 1.0) end end end if lib.returns then for i, rtn in ipairs(lib.returns) do if rtn.type == '...' then - self:getFunctionReturns(func, i):inference('any', 0.0) + self:getFunctionReturns(func, i):setType('any', 0.0) else - self:getFunctionReturns(func, i):inference(rtn.type or 'any', 1.0) + self:getFunctionReturns(func, i):setType(rtn.type or 'any', 1.0) end end end @@ -448,18 +453,10 @@ end function mt:setFunctionReturn(func, index, value) func.hasReturn = true if not func.returns then - func.returns = { - type = 'list', - } + func.returns = createMulti() end if value then - if value.type == 'list' then - for i, v in ipairs(value) do - func.returns[index+i-1] = v - end - else - func.returns[index] = value - end + func.returns[index] = value else func.returns[index] = self:createValue('any', func.source) end @@ -470,17 +467,10 @@ function mt:getFunctionReturns(func, i) return self:createValue('nil') end if not func.returns then - func.returns = { - type = 'list', - } + func.returns = createMulti() 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] + return func.returns:get(i) else return func.returns end @@ -505,13 +495,16 @@ function mt:getName(name, source) local loc = self:loadLocal(name) if loc then source:bindLocal(loc) - return loc + return loc:getValue() end local ENV = self:loadLocal('_ENV') local ENVValue = ENV:getValue() local global = ENVValue:getChild(name) if global then return global + else + global = self:createValue('any') + return global end end @@ -528,39 +521,23 @@ function mt:setName(name, source, value) ENVValue:setChild(name, value) end -function mt:getIndex(obj) - local tp = obj.type - obj.uri = self.chunk.func.uri - if tp == 'name' then - local var = self:getName(obj[1], obj) - local value = self:getValue(var, obj) - self:addInfo(var, 'get', obj) - value:addInfo('get', obj) +function mt:getIndex(source) + self:instantSource(source) + if source.type == 'name' then + local value = self:getName(source[1], source) return value - elseif (tp == 'string' or tp == 'number' or tp == 'boolean') then - return obj[1] + elseif source.type == 'string' or source.type == 'number' or source.type == 'boolean' then + return source[1] else - return self:getExp(obj) + return self:getExp(source) 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 + local dots = self:loadDots(expect) + for _, v in ipairs(dots) do + res[#res+1] = v end end @@ -647,7 +624,7 @@ function mt:getSimple(simple, mode) value = self:selectList(value, 1) if tp == 'call' then - value:inference('function', 0.9) + value:setType('function', 0.9) local args = self:unpackList(obj) if object then table.insert(args, 1, self:getValue(object, obj)) @@ -666,8 +643,8 @@ function mt:getSimple(simple, mode) } parentName = parentName .. '(...)' elseif tp == 'index' then - value:inference('table', 0.8) - value:inference('string', 0.2) + value:setType('table', 0.8) + value:setType('string', 0.2) local child = obj[1] obj.indexName = parentName local index = self:getIndex(child) @@ -689,8 +666,8 @@ function mt:getSimple(simple, mode) parentName = ('%s[?]'):format(parentName) end elseif tp == 'name' then - value:inference('table', 0.8) - value:inference('string', 0.2) + value:setType('table', 0.8) + value:setType('string', 0.2) if mode == 'value' or i < #simple then field = self:getField(value, obj[1], obj) or self:createField(value, obj[1], obj) value = self:getValue(field, obj) @@ -706,14 +683,14 @@ function mt:getSimple(simple, mode) obj.parentName = parentName parentName = parentName .. '.' .. field.key elseif tp == ':' then - value:inference('table', 0.8) - value:inference('string', 0.2) + value:setType('table', 0.8) + value:setType('string', 0.2) object = field simple[i-1].colon = obj colon = colon elseif tp == '.' then - value:inference('table', 0.8) - value:inference('string', 0.2) + value:setType('table', 0.8) + value:setType('string', 0.2) simple[i-1].dot = obj end end @@ -725,6 +702,42 @@ function mt:getSimple(simple, mode) error('Unknow simple mode: ' .. mode) end +function mt:getSimple(simple, max) + local first = simple[1] + self:instantSource(first) + local value = self:getExp(first) + 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) + value = self:getFirstInMulti(value) + + if source.type == 'call' then + local args = self:unpackList(source) + local func = value + if object then + table.insert(args, 1, object) + end + value = self:call(func, args, source) + elseif source.type == 'index' then + local child = source[1] + local index = self:getIndex(child) + value = value:getChild(index) or createValue('any') + elseif source.type == 'name' then + value = value:getChild(source[1]) or createValue('any') + elseif source.type == ':' then + object = value + elseif source.type == '.' then + end + end + return value +end + function mt:isTrue(v) if v:getType() == 'nil' then return false @@ -766,10 +779,10 @@ function mt:getBinary(exp) or op == '<' or op == '>' then - v1:inference('number', 0.9) - v2:inference('number', 0.9) - v1:inference('string', 0.1) - v2:inference('string', 0.1) + v1:setType('number', 0.9) + v2:setType('number', 0.9) + v1:setType('string', 0.1) + v2:setType('string', 0.1) return self:createValue('boolean') elseif op == '~=' or op == '==' @@ -781,12 +794,12 @@ function mt:getBinary(exp) or op == '<<' or op == '>>' then - v1:inference('integer', 0.9) - v2:inference('integer', 0.9) - v1:inference('number', 0.9) - v2:inference('number', 0.9) - v1:inference('string', 0.1) - v2:inference('string', 0.1) + v1:setType('integer', 0.9) + v2:setType('integer', 0.9) + v1:setType('number', 0.9) + v2:setType('number', 0.9) + v1:setType('string', 0.1) + v2:setType('string', 0.1) if math.type(v1:getValue()) == 'integer' and math.type(v2:getValue()) == 'integer' then if op == '|' then return self:createValue('integer', exp, v1:getValue() | v2:getValue()) @@ -802,10 +815,10 @@ function mt:getBinary(exp) end return self:createValue('integer') elseif op == '..' then - v1:inference('string', 0.9) - v2:inference('string', 0.9) - v1:inference('number', 0.1) - v2:inference('number', 0.1) + v1:setType('string', 0.9) + v2:setType('string', 0.9) + v1:setType('number', 0.1) + v2:setType('number', 0.1) if type(v1:getValue()) == 'string' and type(v2:getValue()) == 'string' then return self:createValue('string', nil, v1:getValue() .. v2:getValue()) end @@ -818,8 +831,8 @@ function mt:getBinary(exp) or op == '%' or op == '//' then - v1:inference('number', 0.9) - v2:inference('number', 0.9) + v1:setType('number', 0.9) + v2:setType('number', 0.9) if type(v1:getValue()) == 'number' and type(v2:getValue()) == 'number' then if op == '+' then return self:createValue('number', exp, v1:getValue() + v2:getValue()) @@ -856,20 +869,20 @@ function mt:getUnary(exp) if op == 'not' then return self:createValue('boolean') elseif op == '#' then - v1:inference('table', 0.9) - v1:inference('string', 0.9) + v1:setType('table', 0.9) + v1:setType('string', 0.9) if type(v1:getValue()) == 'string' then return self:createValue('integer', exp, #v1:getValue()) end return self:createValue('integer') elseif op == '-' then - v1:inference('number', 0.9) + v1:setType('number', 0.9) if type(v1:getValue()) == 'number' then return self:createValue('number', exp, -v1:getValue()) end return self:createValue('number') elseif op == '~' then - v1:inference('integer', 0.9) + v1:setType('integer', 0.9) if math.type(v1:getValue()) == 'integer' then return self:createValue('integer', exp, ~v1:getValue()) end @@ -878,13 +891,6 @@ function mt:getUnary(exp) 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) self:instantSource(exp) local tp = exp.type @@ -898,10 +904,7 @@ function mt:getExp(exp) 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, exp) - self:addInfo(var, 'get', exp) - value:addInfo('get', exp) + local value = self:getName(exp[1], exp) return value elseif tp == 'simple' then return self:getSimple(exp, 'value') @@ -984,7 +987,17 @@ function mt:setOne(var, value) end self:instantSource(var) if var.type == 'name' then - else + self:setName(var[1], var, value) + elseif var.type == 'simple' then + local parent = self:getSimple(var, -2) + local key = var[#var] + if key.type == 'index' then + local index = self:getIndex(key[1]) + parent:setChild(index, value) + elseif key.type == 'name' then + local index = key[1] + parent:setChild(index, value) + end end end @@ -1151,7 +1164,7 @@ function mt:doAction(action) self:doLocal(action) elseif tp == 'simple' then -- call - self:getSimple(action, 'value') + self:getSimple(action) elseif tp == 'if' then self:doIf(action) elseif tp == 'loop' then @@ -1230,6 +1243,10 @@ function mt:loadLabel(name) return self.currentFunction:loadLocal(name) end +function mt:loadDots(expect) + return self.currentFunction:loadDots(expect) +end + function mt:getUri() return self.currentFunction and self.currentFunction:getUri() or self.uri end -- cgit v1.2.3