local function getDefaultSource() return { start = 0, finish = 0 } end local mt = {} mt.__index = mt mt.type = 'value' function mt:setValue(value) self._value = value end function mt:getValue() return self._value end function mt:inference(tp, rate) if type(tp) == 'table' then for _, ctp in ipairs(tp) do self:inference(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 not self._type then self._type = {} end local current = self._type[tp] or 0.0 self._type[tp] = current + (1 - current) * rate end function mt:getType() if not self._type then return 'nil' end local mRate = 0.0 local mType for tp, rate in pairs(self._type) do if rate > mRate then mRate = rate mType = tp end end return mType or 'any' end function mt:setMetaTable(metatable, source) if not self._meta then self._meta = {} end local uri = source and source.uri or '' self._meta[uri] = metatable end function mt:createField(name, source) local field = { type = 'field', key = name, uris = {}, } if not self._child then self._child = {} end self._child[name] = field local uri = source and source.uri or '' field.uris[uri] = true self:inference('table', 0.5) return field end function mt:rawGetField(name, source) if not self._child then return nil end local field = self._child[name] if not field then return nil end local uri = source and source.uri or '' field.uris[uri] = true return field end function mt:getMeta(name, source) if not self._meta then return nil end local uri = source and source.uri or '' if self._meta[uri] then local meta = self._meta[uri]:rawGetField(name, source) if meta then return meta end end for _, indexValue in pairs(self._meta) do local meta = indexValue:rawGetField(name, source) if meta then return meta end end return nil end function mt:getChild() if not self._child then self._child = {} end return self._child end function mt:setChild(child) self._child = child end function mt:getField(name, source, mark) local field = self:rawGetField(name, source) if not field then local indexMeta = self:getMeta('__index', source) if not indexMeta then return nil end if not mark then mark = {} end if mark[indexMeta] then return nil end mark[indexMeta] = true return indexMeta.value:getField(name, source, mark) end return field end function mt:rawEachField(callback) if not self._child then return nil end for name, field in pairs(self._child) do local res = callback(name, field) if res ~= nil then return res end end return nil end function mt:eachField(callback, stack, mark) local res = self:rawEachField(callback) if res ~= nil then return res end local indexMeta = self:getMeta('__index') if not indexMeta then return nil end if not mark then mark = {} end if mark[indexMeta] then return nil end mark[indexMeta] = true return indexMeta.value:eachField(callback, stack, mark) end function mt:removeUri(uri) if self._child then for name, field in pairs(self._child) do field.uris[uri] = nil if next(field.uris) then field.value:removeUri(uri) else self._child[name] = nil end end end if self._info then self._info[uri] = nil end if self._meta then self._meta[uri] = nil end end function mt:getDeclarat() if not self._info then return nil end local uri = self.uri or '' local infos = self._info[uri] if not infos then return nil end for _, info in ipairs(infos) do if info.type == 'local' then return info.source end end for _, info in ipairs(infos) do if info.type == 'return' then return info.source end end for _, info in ipairs(infos) do if info.type == 'set' then return info.source end end return nil end function mt:addInfo(tp, source) if source and not source.start then error('Miss start: ' .. table.dump(source)) end if not self._info then self._info = {} end local uri = source and source.uri or '' if not self._info[uri] then self._info[uri] = {} end self._info[uri][#self._info[uri]+1] = { type = tp, source = source or getDefaultSource(), } return self end function mt:eachInfo(callback) if not self._info then return nil end for _, infos in pairs(self._info) do for i = 1, #infos do local res = callback(infos[i]) if res ~= nil then return res end end end return nil end return function (tp, source, value) if tp == '...' then error('Value type cant be ...') end -- TODO lib里的多类型 local self = setmetatable({ source = source or getDefaultSource(), uri = source and source.uri or '', }, mt) if value ~= nil then self:setValue(value) end if type(tp) == 'table' then for i = 1, #tp do self:inference(tp[i], 0.9) end else self:inference(tp, 1.0) end return self end