diff options
Diffstat (limited to 'script/vm/function.lua')
-rw-r--r-- | script/vm/function.lua | 553 |
1 files changed, 0 insertions, 553 deletions
diff --git a/script/vm/function.lua b/script/vm/function.lua deleted file mode 100644 index be58bf7c..00000000 --- a/script/vm/function.lua +++ /dev/null @@ -1,553 +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) - if param:getSource()[1] then - param:getSource()[1]:set('emmy function', self) - end - 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, -} |