diff options
Diffstat (limited to 'script/vm/value.lua')
-rw-r--r-- | script/vm/value.lua | 634 |
1 files changed, 0 insertions, 634 deletions
diff --git a/script/vm/value.lua b/script/vm/value.lua deleted file mode 100644 index 5de0d8e8..00000000 --- a/script/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, -} |