Первый фикс

Пачки некоторых позиций увеличены
This commit is contained in:
2024-03-01 20:53:32 +03:00
commit 7c9c708c92
23653 changed files with 767936 additions and 0 deletions

View File

@@ -0,0 +1,576 @@
--- A collection library to simplify sequential table operations
--
-- local Enumerable = require('__stdlib__/stdlib/vendor/enumerable')
-- Enumerable.create({1,2,3})
-- @classmod Vendor.Enumerable
-- @author Billiam
local Enumerable = {}
Enumerable.mt = {
__index = function(self, key)
return Enumerable[key] or self._data[key]
end
}
--- Tests tables for numeric keys with no gaps
-- @tparam table t Table to check
-- @treturn boolean True if table is sequence-like, false otherwise
local function isSequence(t)
local i = 0
for _ in pairs(t) do
i = i + 1
if t[i] == nil then return false end
end
return true
end
--- Whether the item passed in may be called as a function
-- @param f Item to test for callability
-- @treturn boolean True if passed in item may be called, false otherwise
local function isCallable(f)
local t = type(f)
if t == 'function' then
return true
end
if t == 'table' then
local meta = getmetatable(f)
return meta and type(meta.__call) == 'function'
end
return false
end
--- Enumerable constructor.
-- If no collection is provided, a new empty table will be generated.
--
-- @usage
-- collection = Enumerable.create({123})
-- @tparam ?table collection Sequential table to wrap
-- @treturn enumerable A new collection instance
-- @raise 'Enumerable data must be a sequence' if given a non-sequential table
function Enumerable.create(collection)
if collection and not (type(collection) == 'table' and isSequence(collection)) then
error('Enumerable data must be a sequence')
end
local instance = {
--- Internal collection data
-- @table _data
_data = collection or {}
}
setmetatable(instance, Enumerable.mt)
return instance
end
--- Return the unwrapped collection data.
-- @usage
-- collectionData = collection:to_table()
-- @treturn table
function Enumerable:data()
return self._data
end
--- Create a shallow copy of the unwrapped collection data.
-- @usage
-- clonedData = collection:to_table()
-- @treturn table
function Enumerable:to_table()
local meta = getmetatable(self._data)
local target = {}
for k, v in pairs(self._data) do target[k] = v end
setmetatable(target, meta)
return target
end
--- Pass all elements in the collection to a callback.
-- @usage
-- collection:each(function(value, index) ... end)
-- @tparam callable callback
-- @treturn enumerable The collection instance
function Enumerable:each(callback)
for i,v in ipairs(self._data) do
callback(v, i)
end
return self
end
--- Pass all elements in collection to a callback.
-- returns a new enumerable instance containing values
-- returned by the callback.
-- @usage
-- collection = Enumerable.create({1, 2, 3})
-- collection:map(function(value, index) return value* 2 end)
-- -> Enumerable containing {2, 4, 6}
-- @tparam callable callback
-- @treturn enumerable New enumerable instance
function Enumerable:map(callback)
local map = {}
for i,v in ipairs(self._data) do
local result = callback(v, i)
if result ~= nil then
table.insert(map, result)
end
end
return Enumerable.create(map)
end
--- Find the position of the first item in collection for which
-- the callback returns true.
-- @usage
-- collection = Collection.create({0, 1, 2, 3, 4})
-- collection:findIndex(function(value, index) return value > 2 end)
-- -> 4
-- @tparam callable callback
-- @treturn int the position of the matched element
function Enumerable:find_index(callback)
for i,v in ipairs(self._data) do
if callback(v, i) then
return i
end
end
end
--- Whether the collection has no elements.
-- @usage collection = Enumerable.create()
-- if collection:empty() then
-- print('Collection is empty')
-- end
-- -> Collection is empty
-- @treturn bool
function Enumerable:empty()
return #self._data == 0
end
--- Return the first element or elements in the collection.
-- @see Enumerable:last
-- @usage
-- collection = Enumerable.create({1,2,3,4})
-- collection:first()
-- -> 1
-- collection:first(3)
-- -> {1,2,3}
-- @tparam ?int n Number of elements to return. If absent, the first item will be returned.
-- @treturn table|*
function Enumerable:first(n)
if not n or n == 1 then
return self._data[1]
end
local list = {}
n = math.min(n, #self._data)
for i=1,n do
table.insert(list, self._data[i])
end
return list
end
--- Return the last element or elements in the collection.
-- @see Enumerable:first
-- @usage
-- collection = Enumerable.create({1,2,3,4})
-- collection:last()
-- -> 4
-- collection:last(3)
-- -> {2, 3, 4}
-- @tparam ?int n Number of elements to return. If absent, the last item will be returned.
-- @treturn table
function Enumerable:last(n)
if not n or n == 1 then
return self._data[#self._data]
end
local list = {}
n = math.max(1, #self._data - (n - 1))
for i=n,#self._data do
table.insert(list, self._data[i])
end
return list
end
--- Return the number of items in the collection.
-- If a callback is given, count will return the
-- number of elements for which the callback returns true
-- @usage
-- collection = Enumerable.create({1,2,3})
-- collection:count()
-- -> 3
-- collection:count(function(value, index) return value % 2 == 0 end)
-- -> 1
-- @tparam callable callback Callback used to determine whether element should be counted
-- @treturn int
function Enumerable:count(callback)
if not callback then
return #self._data
end
local count = 0
for i,v in ipairs(self._data) do
if callback(v, i) then
count = count + 1
end
end
return count
end
--- Append the contents of one table onto the end of the existing enumerable.
-- @usage
-- pets = Enumerable:create({'dog', 'cat'})
-- pets:concat({'turtle', 'wizard'})
-- -> pets now contains {'dog', 'cat', 'turtle', 'wizard'}
-- @tparam table other Table with content to append to enumerable
-- @treturn enumerable The enumerable instance
function Enumerable:concat(other)
return self:push(unpack(other))
end
--- Combine elements of enumerable by passing all items to a callback.
-- Values returned by the callback will be used as the accumulator value
-- for subsequent callbacks.
-- @usage
-- numbers = Enumerable.create({1,2,3})
-- numbers:reduce(function(accumulator, value) return (accumulator or 0) + value end)
-- -> 6
-- numbers:reduce(20, function(accumulator, value) return accumulator + value end)
-- -> 26
-- @tparam ?int initial Initial value for accumulator
-- @tparam callable callback
-- @return Accumulator value
function Enumerable:reduce(initial, callback)
if not callback then
if isCallable(initial) then
callback = initial
initial = nil
else
error('Callback must be a function or table with a __call metamethod')
end
end
local reduce = initial
for i,v in ipairs(self._data) do
reduce = callback(reduce, v, i)
end
return reduce
end
--- Find the lowest value in the enumerable instance.
-- If a callback is provided, the return value will be used
-- to determine the lowest value.
-- @usage
-- strings = Enumerable.create({'aaaaaa', 'bbb', 'c'})
-- strings:min()
-- -> 'aaaaa'
-- strings:min(function(value) return #value end)
-- -> 'c'
-- @tparam ?callable callback
-- @return Lowest value
function Enumerable:min(callback)
callback = callback or function(v) return v end
local lowestValue
return self:reduce(function(output, v)
local result = callback(v)
if not output or (result and result < lowestValue) then
lowestValue = result
return v
end
return output
end)
end
--- Find the highest value in the enumerable instance.
-- If a callback is provided, the return value will be used
-- to determine the highest value.
-- @usage
-- strings = Enumerable.create({'aaaaaa', 'bbb', 'c'})
-- strings:max()
-- -> 'c'
-- strings:max(function(value) return #value end)
-- -> 'aaaaa'
-- @tparam ?callable callback
-- @return Highest value
function Enumerable:max(callback)
callback = callback or function(v) return v end
local highestValue
return self:reduce(function(output, v)
local result = callback(v)
if not output or (result and result > highestValue) then
highestValue = result
return v
end
return output
end)
end
--- Find the highest and lowest values in the enumerable.
-- If a callback is provided, the return value will be used
-- to determine the highest and lowest values.
-- @usage
-- numbers = Enumerable.create({6,3,1,5,2,4})
-- lowest, highest = numbers:minmax()
-- -> (1,6)
-- strings:max(function(value) return 10 - value end)
-- -> (6, 1)
-- @tparam ?callable callback
-- @return Lowest value
-- @return Highest value
function Enumerable:minmax(callback)
return self:min(callback), self:max(callback)
end
--- Sort the enumerable by optional callback in place.
-- If a callback is not provided, data will be sorted in ascending order.
-- If callback is provided, it will be passed two table elements, and should
-- return true if the first element should appear first, otherwise false.
-- See also: [table.sort documentation](http://www.lua.org/manual/5.1/manual.html#pdf-table.sort)
-- @usage
-- numbers = Enumerable.create({2,1,3})
-- numbers:sort()
-- -> numbers now contains {1,2,3}
-- numbers:sort(function(a, b) return b < a end)
-- -> numbers now contains {3,2,1}
-- @tparam ?callable callback sort method
-- @treturn enumerable The collection instance
function Enumerable:sort(callback)
table.sort(self._data, callback)
return self
end
--- Add one or more items to the enumerable.
-- @usage
-- items = Enumerable.create({1,2,3})
-- items:push(4, 5)
-- -> items contains {1,2,3,4,5}
-- @param ... Items to append
-- @treturn enumerable The collection instance
function Enumerable:push(...)
for i,v in ipairs({...}) do
table.insert(self._data, v)
end
return self
end
--- Remove and return the last item from the collection.
-- @usage
-- items = Enumerable.create({1,2,3})
-- items:pop()
-- -> returns 3
-- -> items now contains {1,2}
-- @treturn enumerable The collection instance
function Enumerable:pop()
return table.remove(self._data, #self._data)
end
--- Remove and return the first item from the collection.
-- @usage
-- items = Enumerable.create({1,2,3})
-- items:shift()
-- -> returns 1
-- -> items now contains {2,3}
-- @treturn enumerable The collection instance
function Enumerable:shift()
return table.remove(self._data, 1)
end
--- Insert one or more items into the beginning of the collection.
-- @usage
-- items = Enumerable.create({4,5,6})
-- items:unshift(1,2,3)
-- -> Items now contains {1,2,3,4,5,6}
-- @param ... Elements to insert
-- @treturn enumerable The collection instance
function Enumerable:unshift(...)
for i,v in ipairs({...}) do
table.insert(self._data, i, v)
end
return self
end
--- Returns the first element in the collection where the callback returns true.
-- @usage
-- numbers = Enumerable.create({20, 30, 40})
-- numbers:find(function(value, index) return value > 25 end)
-- -> 30
-- @tparam callable callback
-- @return Matching item
function Enumerable:find(callback)
for i,v in ipairs(self._data) do
if callback(v, i) then
return v
end
end
end
--- Create a new collection with elements which the callback returns false.
-- @usage
-- items = Enumerable.create({1,2,3,4,5,6})
-- odd = Enumerable:reject(function(value, index) return value % 2 == 0 end)
-- -> Enumerable containing {1,3,5}
-- @tparam callable callback
-- @treturn enumerable New collection instance
function Enumerable:reject(callback)
local reject = {}
for i,v in ipairs(self._data) do
if not callback(v, i) then
table.insert(reject, v)
end
end
return Enumerable.create(reject)
end
--- Create a new collection with elements which the callback returns true.
-- @usage
-- items = Enumerable.create({1,2,3,4,5,6})
-- even = Enumerable:select(function(value, index) return value % 2 == 0 end)
-- -> Enumerable containing {2,4,6}
-- @tparam callable callback
-- @treturn enumerable New collection instance
-- @alias find_all
function Enumerable:select(callback)
local select = {}
for i,v in ipairs(self._data) do
if callback(v, i) then
table.insert(select, v)
end
end
return Enumerable.create(select)
end
--- Returns true if callback returns truthy for all elements in the collection.
-- @usage
-- items = Enumerable.create({10, 20, 30})
-- items:all(function(value, index) return value > 5 end)
-- -> true
-- items:all(function(value, index) return value < 25 end)
-- -> false
-- @tparam callable callback
-- @treturn bool
function Enumerable:all(callback)
for i,v in ipairs(self._data) do
if not callback(v, i) then
return false
end
end
return true
end
--- Returns true if callback returns truthy for any element in the collection.
-- @usage
-- items = Enumerable.create({10, 20, 30})
-- items:any(function(value, index) return value > 25 end)
-- -> true
-- items:any(function(value, index) return value > 30 end)
-- -> false
-- @tparam callable callback
-- @treturn bool
function Enumerable:any(callback)
for i,v in ipairs(self._data) do
if callback(v, i) then
return true
end
end
return false
end
--- Groups elements into collections based on the result of the provided callback.
-- Resulting table will have keys matching the returned value of the callback, and
-- values as a table of elements which returned that value.
-- @usage
-- numbers = Enumerable.create({1,2,3,4,5,6})
-- result = Enumerable.group_by(function(value, index) return value % 3 end)
-- result[0]
-- -> Enumerable containing {3, 6}
-- result[1]
-- -> Enumerable containing {2, 5}
-- result[2]
-- -> Enumerable containing {1, 4}
-- @tparam callable callback
-- @treturn table
function Enumerable:group_by(callback)
local groups = {}
for i,v in ipairs(self._data) do
local criteria = callback(v, i)
groups[criteria] = groups[criteria] or Enumerable.create()
groups[criteria]:push(v)
end
return groups
end
--- Split enumerable into two groups, based on the true or false result of the callback.
--
-- Aliases: find_all, detect
--
-- @usage
-- numbers = Enumerable.create({1,2,3,4,5,6})
-- even, odd = Enumerable:partition(function(value, index) return value % 2 == 1 end)
-- -> even is a collection containing {2, 4, 6}
-- -> odd is a collection containing {1, 3, 5}
-- @tparam callable callback
-- @treturn enumerable Collection containing items which returned true
-- @treturn enumerable Collection containing items which returned false
function Enumerable:partition(callback)
local truthyCallback = function(v, i)
return callback(v, i) and true or false
end
local results = self:group_by(truthyCallback)
return results[true] or Enumerable.create(), results[false] or Enumerable.create()
end
---
-- @function Enumerable:find_all
-- @see Enumerable:select
Enumerable.find_all = Enumerable.select
---
-- @function Enumerable:detect
-- @see Enumerable:select
Enumerable.detect = Enumerable.select
---
-- @function Enumerable:collect
-- @see Enumerable:map
Enumerable.collect = Enumerable.map
---
-- @function Enumerable:inject
-- @see Enumerable:reduce
Enumerable.inject = Enumerable.reduce
return Enumerable

418
stdlib_1.4.8/stdlib/vendor/inspect.lua vendored Normal file
View File

@@ -0,0 +1,418 @@
local inspect = {
_VERSION = 'inspect.lua 3.1.0',
_URL = 'http://github.com/kikito/inspect.lua',
_DESCRIPTION = 'human-readable representations of tables',
_LICENSE = [[
MIT LICENSE
Copyright (c) 2013 Enrique García Cota
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
}
local tostring = tostring
inspect.KEY =
setmetatable(
{},
{
__tostring = function()
return 'inspect.KEY'
end
}
)
inspect.METATABLE =
setmetatable(
{},
{
__tostring = function()
return 'inspect.METATABLE'
end
}
)
-- Apostrophizes the string if it has quotes, but not aphostrophes
-- Otherwise, it returns a regular quoted string
local function smartQuote(str)
if str:match('"') and not str:match("'") then
return "'" .. str .. "'"
end
return '"' .. str:gsub('"', '\\"') .. '"'
end
-- \a => '\\a', \0 => '\\0', 31 => '\31'
local shortControlCharEscapes = {
['\a'] = '\\a',
['\b'] = '\\b',
['\f'] = '\\f',
['\n'] = '\\n',
['\r'] = '\\r',
['\t'] = '\\t',
['\v'] = '\\v'
}
local longControlCharEscapes = {} -- \a => nil, \0 => \000, 31 => \031
for i = 0, 31 do
local ch = string.char(i)
if not shortControlCharEscapes[ch] then
shortControlCharEscapes[ch] = '\\' .. i
longControlCharEscapes[ch] = string.format('\\%03d', i)
end
end
local function escape(str)
return (str:gsub('\\', '\\\\'):gsub('(%c)%f[0-9]', longControlCharEscapes):gsub('%c', shortControlCharEscapes))
end
local function isIdentifier(str)
return type(str) == 'string' and str:match('^[_%a][_%a%d]*$')
end
local function isSequenceKey(k, sequenceLength)
return type(k) == 'number' and 1 <= k and k <= sequenceLength and math.floor(k) == k
end
local defaultTypeOrders = {
['number'] = 1,
['boolean'] = 2,
['string'] = 3,
['table'] = 4,
['function'] = 5,
['userdata'] = 6,
['thread'] = 7
}
local function sortKeys(a, b)
local ta, tb = type(a), type(b)
-- strings and numbers are sorted numerically/alphabetically
if ta == tb and (ta == 'string' or ta == 'number') then
return a < b
end
local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb]
-- Two default types are compared according to the defaultTypeOrders table
if dta and dtb then
return defaultTypeOrders[ta] < defaultTypeOrders[tb]
elseif dta then
return true -- default types before custom ones
elseif dtb then
return false -- custom types after default ones
end
-- custom types are sorted out alphabetically
return ta < tb
end
-- For implementation reasons, the behavior of rawlen & # is "undefined" when
-- tables aren't pure sequences. So we implement our own # operator.
local function getSequenceLength(t)
local len = 1
local v = rawget(t, len)
while v ~= nil do
len = len + 1
v = rawget(t, len)
end
return len - 1
end
local function getNonSequentialKeys(t)
local keys = {}
local sequenceLength = getSequenceLength(t)
for k, _ in pairs(t) do
if not isSequenceKey(k, sequenceLength) then
table.insert(keys, k)
end
end
table.sort(keys, sortKeys)
return keys, sequenceLength
end
local function getToStringResultSafely(t, mt)
local __tostring = type(mt) == 'table' and rawget(mt, '__tostring')
local str, ok
if type(__tostring) == 'function' then
ok, str = pcall(__tostring, t)
str = ok and str or 'error: ' .. tostring(str)
end
if type(str) == 'string' and #str > 0 then
return str
end
end
local function countTableAppearances(t, tableAppearances)
tableAppearances = tableAppearances or {}
if type(t) == 'table' then
if not tableAppearances[t] then
tableAppearances[t] = 1
for k, v in pairs(t) do
countTableAppearances(k, tableAppearances)
countTableAppearances(v, tableAppearances)
end
countTableAppearances(getmetatable(t), tableAppearances)
else
tableAppearances[t] = tableAppearances[t] + 1
end
end
return tableAppearances
end
local copySequence = function(s)
local copy, len = {}, #s
for i = 1, len do
copy[i] = s[i]
end
return copy, len
end
local function makePath(path, ...)
local keys = {...}
local newPath, len = copySequence(path)
for i = 1, #keys do
newPath[len + i] = keys[i]
end
return newPath
end
local function processRecursive(process, item, path, visited)
if item == nil then
return nil
end
if visited[item] then
return visited[item]
end
local processed = process(item, path)
if type(processed) == 'table' then
local processedCopy = {}
visited[item] = processedCopy
local processedKey
for k, v in pairs(processed) do
processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited)
if processedKey ~= nil then
processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited)
end
end
local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited)
if type(mt) ~= 'table' then
mt = nil
end -- ignore not nil/table __metatable field
setmetatable(processedCopy, mt)
processed = processedCopy
end
return processed
end
-------------------------------------------------------------------
local Inspector = {}
local Inspector_mt = {__index = Inspector}
function Inspector:puts(...)
local args = {...}
local buffer = self.buffer
local len = #buffer
for i = 1, #args do
len = len + 1
buffer[len] = args[i]
end
end
function Inspector:down(f)
self.level = self.level + 1
f()
self.level = self.level - 1
end
function Inspector:tabify()
self:puts(self.newline, string.rep(self.indent, self.level))
end
function Inspector:alreadyVisited(v)
return self.ids[v] ~= nil
end
function Inspector:getId(v)
local id = self.ids[v]
if not id then
local tv = type(v)
id = (self.maxIds[tv] or 0) + 1
self.maxIds[tv] = id
self.ids[v] = id
end
return tostring(id)
end
function Inspector:putKey(k, arraykey)
if arraykey or (not self.longkeys and isIdentifier(k)) then
return self:puts(k)
end
self:puts(arraykey and '' or '[')
self:putValue(k)
self:puts(arraykey and '' or ']')
end
function Inspector:putTable(t)
if t == inspect.KEY or t == inspect.METATABLE then
self:puts(tostring(t))
elseif self:alreadyVisited(t) then
self:puts('<table ', self:getId(t), '>')
elseif self.level >= self.depth then
self:puts('{...}')
else
if self.tableAppearances[t] > 1 then
self:puts('<', self:getId(t), '>')
end
local nonSequentialKeys, sequenceLength = getNonSequentialKeys(t)
local mt = getmetatable(t)
local toStringResult = getToStringResultSafely(t, mt)
self:puts('{')
self:down(
function()
if toStringResult then
self:puts(' -- ', escape(toStringResult))
if sequenceLength >= 1 then
self:tabify()
end
end
local count = 0
for i = 1, sequenceLength do
if count > 0 then
self:puts(',')
end
if self.arraytabify then
self:tabify()
else
self:puts(' ')
end
if self.arraykeys then
self:putKey(i, self.arraykeys)
self:puts(' = ')
end
self:putValue(t[i])
count = count + 1
end
for _, k in ipairs(nonSequentialKeys) do
if count > 0 then
self:puts(',')
end
self:tabify()
self:putKey(k)
self:puts(' = ')
self:putValue(t[k])
count = count + 1
end
if type(mt) == 'table' then
if count > 0 then
self:puts(',')
end
self:tabify()
self:puts('<metatable> = ')
self:putValue(mt)
end
end
)
if #nonSequentialKeys > 0 or type(mt) == 'table' or self.arraytabify then -- result is multi-lined. Justify closing }
self:tabify()
elseif sequenceLength > 0 then -- array tables have one extra space before closing }
self:puts(' ')
end
self:puts('}')
end
end
function Inspector:putValue(v)
local tv = type(v)
if tv == 'string' then
self:puts(smartQuote(escape(v)))
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or tv == 'cdata' or tv == 'ctype' then
self:puts(tostring(v))
elseif tv == 'table' then
self:putTable(v)
else
self:puts('<', tv, ' ', self:getId(v), '>')
end
end
-------------------------------------------------------------------
function inspect.inspect(root, options)
options = options or {}
local depth = options.depth or math.huge
local newline = options.newline or '\n'
local indent = options.indent or ' '
local process = options.process
local longkeys = options.longkeys
local arraykeys = options.arraykeys
local arraytabify = options.arraytabify
local metatables = options.metatables
if process then
root = processRecursive(process, root, {}, {})
end
local inspector =
setmetatable(
{
depth = depth,
level = 0,
buffer = {},
ids = {},
maxIds = {},
newline = newline,
indent = indent,
longkeys = longkeys,
arraykeys = arraykeys,
arraytabify = arraytabify,
metatables = metatables,
tableAppearances = countTableAppearances(root)
},
Inspector_mt
)
inspector:putValue(root)
return table.concat(inspector.buffer)
end
setmetatable(
inspect,
{
__call = function(_, ...)
return inspect.inspect(...)
end
}
)
return inspect

231
stdlib_1.4.8/stdlib/vendor/semver.lua vendored Normal file
View File

@@ -0,0 +1,231 @@
local semver = {
_VERSION = '1.2.1',
_DESCRIPTION = 'semver for Lua',
_URL = 'https://github.com/kikito/semver.lua',
_LICENSE = [[
MIT LICENSE
Copyright (c) 2015 Enrique García Cota
Permission is hereby granted, free of charge, to any person obtaining a
copy of tother software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and tother permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
}
local function checkPositiveInteger(number, name)
assert(number >= 0, name .. ' must be a valid positive number')
assert(math.floor(number) == number, name .. ' must be an integer')
end
local function present(value)
return value and value ~= ''
end
-- splitByDot("a.bbc.d") == {"a", "bbc", "d"}
local function splitByDot(str)
str = str or ''
local t, count = {}, 0
str:gsub(
'([^%.]+)',
function(c)
count = count + 1
t[count] = c
end
)
return t
end
local function parsePrereleaseAndBuildWithSign(str)
local prereleaseWithSign, buildWithSign = str:match('^(-[^+]+)(+.+)$')
if not (prereleaseWithSign and buildWithSign) then
prereleaseWithSign = str:match('^(-.+)$')
buildWithSign = str:match('^(+.+)$')
end
assert(prereleaseWithSign or buildWithSign, ('The parameter %q must begin with + or - to denote a prerelease or a build'):format(str))
return prereleaseWithSign, buildWithSign
end
local function parsePrerelease(prereleaseWithSign)
if prereleaseWithSign then
local prerelease = prereleaseWithSign:match('^-(%w[%.%w-]*)$')
assert(prerelease, ('The prerelease %q is not a slash followed by alphanumerics, dots and slashes'):format(prereleaseWithSign))
return prerelease
end
end
local function parseBuild(buildWithSign)
if buildWithSign then
local build = buildWithSign:match('^%+(%w[%.%w-]*)$')
assert(build, ('The build %q is not a + sign followed by alphanumerics, dots and slashes'):format(buildWithSign))
return build
end
end
local function parsePrereleaseAndBuild(str)
if not present(str) then
return nil, nil
end
local prereleaseWithSign, buildWithSign = parsePrereleaseAndBuildWithSign(str)
local prerelease = parsePrerelease(prereleaseWithSign)
local build = parseBuild(buildWithSign)
return prerelease, build
end
local function parseVersion(str)
local sMajor, sMinor, sPatch, sPrereleaseAndBuild = str:match('^(%d+)%.?(%d*)%.?(%d*)(.-)$')
assert(type(sMajor) == 'string', ('Could not extract version number(s) from %q'):format(str))
local major, minor, patch = tonumber(sMajor), tonumber(sMinor), tonumber(sPatch)
local prerelease, build = parsePrereleaseAndBuild(sPrereleaseAndBuild)
return major, minor, patch, prerelease, build
end
-- return 0 if a == b, -1 if a < b, and 1 if a > b
local function compare(a, b)
return a == b and 0 or a < b and -1 or 1
end
local function compareIds(myId, otherId)
if myId == otherId then
return 0
elseif not myId then
return -1
elseif not otherId then
return 1
end
local selfNumber, otherNumber = tonumber(myId), tonumber(otherId)
if selfNumber and otherNumber then -- numerical comparison
-- numericals are always smaller than alphanums
return compare(selfNumber, otherNumber)
elseif selfNumber then
return -1
elseif otherNumber then
return 1
else
return compare(myId, otherId) -- alphanumerical comparison
end
end
local function smallerIdList(myIds, otherIds)
local myLength = #myIds
local comparison
for i = 1, myLength do
comparison = compareIds(myIds[i], otherIds[i])
if comparison ~= 0 then
return comparison == -1
end
-- if comparison == 0, continue loop
end
return myLength < #otherIds
end
local function smallerPrerelease(mine, other)
if mine == other or not mine then
return false
elseif not other then
return true
end
return smallerIdList(splitByDot(mine), splitByDot(other))
end
local methods = {}
function methods:nextMajor()
return semver(self.major + 1, 0, 0)
end
function methods:nextMinor()
return semver(self.major, self.minor + 1, 0)
end
function methods:nextPatch()
return semver(self.major, self.minor, self.patch + 1)
end
local mt = {__index = methods}
function mt:__eq(other)
return self.major == other.major and self.minor == other.minor and self.patch == other.patch and self.prerelease == other.prerelease
-- notice that build is ignored for precedence in semver 2.0.0
end
function mt:__lt(other)
if self.major ~= other.major then
return self.major < other.major
end
if self.minor ~= other.minor then
return self.minor < other.minor
end
if self.patch ~= other.patch then
return self.patch < other.patch
end
return smallerPrerelease(self.prerelease, other.prerelease)
-- notice that build is ignored for precedence in semver 2.0.0
end
-- This works like the "pessimisstic operator" in Rubygems.
-- if a and b are versions, a ^ b means "b is backwards-compatible with a"
-- in other words, "it's safe to upgrade from a to b"
function mt:__pow(other)
if self.major == 0 then
return self == other
end
return self.major == other.major and self.minor <= other.minor
end
function mt:__tostring()
local buffer = {('%d.%d.%d'):format(self.major, self.minor, self.patch)}
if self.prerelease then
table.insert(buffer, '-' .. self.prerelease)
end
if self.build then
table.insert(buffer, '+' .. self.build)
end
return table.concat(buffer)
end
local function new(major, minor, patch, prerelease, build)
assert(major, 'At least one parameter is needed')
if type(major) == 'string' then
major, minor, patch, prerelease, build = parseVersion(major)
end
patch = patch or 0
minor = minor or 0
checkPositiveInteger(major, 'major')
checkPositiveInteger(minor, 'minor')
checkPositiveInteger(patch, 'patch')
local result = {major = major, minor = minor, patch = patch, prerelease = prerelease, build = build}
return setmetatable(result, mt)
end
setmetatable(
semver,
{
__call = function(_, ...)
return new(...)
end
}
)
semver._VERSION = semver(semver._VERSION)
return semver

146
stdlib_1.4.8/stdlib/vendor/serpent.lua vendored Normal file
View File

@@ -0,0 +1,146 @@
--Serpent version used in factorio
do
local n, v = "serpent", "0.30" -- (C) 2012-17 Paul Kulchenko; MIT License
local c, d = "Paul Kulchenko", "Lua serializer and pretty printer"
local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'}
local badtype = {thread = true, userdata = true, cdata = true}
local getmetatable = debug and debug.getmetatable or getmetatable
local pairs = function(t) return next, t end -- avoid using __pairs in Lua 5.2+
local keyword, globals, G = {}, {}, (_G or _ENV)
for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false',
'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat',
'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end
for k,v in pairs(G) do globals[v] = k end -- build func to name mapping
for _,g in ipairs({'coroutine', 'debug', 'io', 'math', 'string', 'table', 'os'}) do
for k,v in pairs(type(G[g]) == 'table' and G[g] or {}) do globals[v] = g..'.'..k end end
local function s(t, opts)
local name, indent, fatal, maxnum = opts.name, opts.indent, opts.fatal, opts.maxnum
local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge
local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge)
local maxlen, metatostring = tonumber(opts.maxlength), opts.metatostring
local iname, comm = '_'..(name or ''), opts.comment and (tonumber(opts.comment) or math.huge)
local numformat = opts.numformat or "%.17g"
local seen, sref, syms, symn = {}, {'local '..iname..'={}'}, {}, 0
local function gensym(val) return '_'..(tostring(tostring(val)):gsub("[^%w]",""):gsub("(%d%w+)",
-- tostring(val) is needed because __tostring may return a non-string value
function(s) if not syms[s] then symn = symn+1; syms[s] = symn end return tostring(syms[s]) end)) end
local function safestr(s) return type(s) == "number" and tostring(huge and snum[tostring(s)] or numformat:format(s))
or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026
or ("%q"):format(s):gsub("\\010","n"):gsub("\\026","\\\\026") end
local function comment(s,l) return comm and (l or 0) < comm and ' --[['..select(2, pcall(tostring, s))..']]' or '' end
local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal
and safestr(select(2, pcall(tostring, s))) or error("Can't serialize "..tostring(s)) end
local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r']
local n = name == nil and '' or name
local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n]
local safe = plain and n or '['..safestr(n)..']'
return (path or '')..(plain and path and '.' or '')..safe, safe end
local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(k, o, n) -- k=keys, o=originaltable, n=padding
local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'}
local function padnum(d) return ("%0"..tostring(maxn).."d"):format(tonumber(d)) end
table.sort(k, function(a,b)
-- sort numeric keys first: k[key] is not nil for numerical keys
return (k[a] ~= nil and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum))
< (k[b] ~= nil and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end
local function val2str(t, name, indent, insref, path, plainindex, level)
local ttype, level = type(t), (level or 0)
local spath, sname = safename(path, name)
local tag = plainindex and
((type(name) == "number") and '' or name..space..'='..space) or
(name ~= nil and sname..space..'='..space or '')
if seen[t] then -- already seen this element
sref[#sref+1] = spath..space..'='..space..seen[t]
return tag..'nil'..comment('ref', level) end
-- protect from those cases where __tostring may fail
if metatostring ~= false then
local mt = getmetatable(t)
if type(mt) == 'table' then
local to, tr = pcall(function() return mt.__tostring(t) end)
local so, sr = pcall(function() return mt.__serialize(t) end)
if (to or so) then -- knows how to serialize itself
seen[t] = insref or spath
t = so and sr or tr
ttype = type(t)
end -- new value falls through to be serialized
end
end
if ttype == "table" then
if level >= maxl then return tag..'{}'..comment('maxlvl', level) end
seen[t] = insref or spath
if next(t) == nil then return tag..'{}'..comment(t, level) end -- table empty
if maxlen and maxlen < 0 then return tag..'{}'..comment('maxlen', level) end
local maxn, o, out = math.min(#t, maxnum or #t), {}, {}
for key = 1, maxn do o[key] = key end
if not maxnum or #o < maxnum then
local n = #o -- n = n + 1; o[n] is much faster than o[#o+1] on large tables
for key in pairs(t) do if o[key] ~= key then n = n + 1; o[n] = key end end end
if maxnum and #o > maxnum then o[maxnum+1] = nil end
if opts.sortkeys and #o > maxn then alphanumsort(o, t, opts.sortkeys) end
local sparse = sparse and #o > maxn -- disable sparsness if only numeric keys (shorter output)
for n, key in ipairs(o) do
local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse
if opts.valignore and opts.valignore[value] -- skip ignored values; do nothing
or opts.keyallow and not opts.keyallow[key]
or opts.keyignore and opts.keyignore[key]
or opts.valtypeignore and opts.valtypeignore[type(value)] -- skipping ignored value types
or sparse and value == nil then -- skipping nils; do nothing
elseif ktype == 'table' or ktype == 'function' or badtype[ktype] then
if not seen[key] and not globals[key] then
sref[#sref+1] = 'placeholder'
local sname = safename(iname, gensym(key)) -- iname is table for local variables
sref[#sref] = val2str(key,sname,indent,sname,iname,true) end
sref[#sref+1] = 'placeholder'
local path = seen[t]..'['..tostring(seen[key] or globals[key] or gensym(key))..']'
sref[#sref] = path..space..'='..space..tostring(seen[value] or val2str(value,nil,indent,path))
else
out[#out+1] = val2str(value,key,indent,insref,seen[t],plainindex,level+1)
if maxlen then
maxlen = maxlen - #out[#out]
if maxlen < 0 then break end
end
end
end
local prefix = string.rep(indent or '', level)
local head = indent and '{\n'..prefix..indent or '{'
local body = table.concat(out, ','..(indent and '\n'..prefix..indent or space))
local tail = indent and "\n"..prefix..'}' or '}'
return (custom and custom(tag,head,body,tail,level) or tag..head..body..tail)..comment(t, level)
elseif badtype[ttype] then
seen[t] = insref or spath
return tag..globerr(t, level)
elseif ttype == 'function' then
seen[t] = insref or spath
if opts.nocode then return tag.."function() --[[..skipped..]] end"..comment(t, level) end
local ok, res = pcall(string.dump, t)
local func = ok and "((loadstring or load)("..safestr(res)..",'@serialized'))"..comment(t, level)
return tag..(func or globerr(t, level))
else return tag..safestr(t) end -- handle all other types
end
local sepr = indent and "\n" or ";"..space
local body = val2str(t, name, indent) -- this call also populates sref
local tail = #sref>1 and table.concat(sref, sepr)..sepr or ''
local warn = opts.comment and #sref>1 and space.."--[[incomplete output with shared/self-references skipped]]" or ''
return not name and body..warn or "do local "..body..sepr..tail.."return "..name..sepr.."end"
end
local function deserialize(data, opts)
local env = (opts and opts.safe == false) and G
or setmetatable({}, {
__index = function(t,k) return t end,
__call = function(t,...) error("cannot call functions") end
})
local f, res = (loadstring or load)('return '..data, nil, nil, env)
if not f then f, res = (loadstring or load)(data, nil, nil, env) end
if not f then return f, res end
if setfenv then setfenv(f, env) end
return pcall(f)
end
local function merge(a, b) if b then for k,v in pairs(b) do a[k] = v end end; return a; end
return { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s,
load = deserialize,
dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true, metatostring = false}, opts)) end,
line = function(a, opts) return s(a, merge({sortkeys = true, comment = false, metatostring = false}, opts)) end,
block = function(a, opts) return s(a, merge({indent = ' ', sortkeys = true, comment = false, metatostring = false}, opts)) end }
end

384
stdlib_1.4.8/stdlib/vendor/version.lua vendored Normal file
View File

@@ -0,0 +1,384 @@
---
-- Version comparison library for Lua.
--
-- Comparison is simple and straightforward, with basic support for SemVer.
--
-- @usage
-- local version = require("version")
--
-- -- create a version and perform some comparisons
-- local v = version("3.1.0")
-- assert( v == version("3.1")) -- missing elements default to zero, and hence are equal
-- assert( v > version("3.0"))
--
-- -- create a version range, and check whether a version is within that range
-- local r = version.range("2.75", "3.50.3")
-- assert(r:matches(v))
--
-- -- create a set of multiple ranges, adding elements in a chained fashion
-- local compatible = version.set("1.1","1.2"):allowed("2.1", "2.5"):disallowed("2.3")
--
-- assert(compatible:matches("1.1.3"))
-- assert(compatible:matches("1.1.3"))
-- assert(compatible:matches("2.4"))
-- assert(not compatible:matches("2.0"))
-- assert(not compatible:matches("2.3"))
--
-- -- print a formatted set
-- print(compatible) --> "1.1 to 1.2 and 2.1 to 2.5, but not 2.3"
--
-- -- create an upwards compatibility check, allowing all versions 1.x
-- local c = version.set("1.0","2.0"):disallowed("2.0")
-- assert(c:matches("1.4"))
-- assert(not c:matches("2.0"))
--
-- -- default parsing
-- print(version("5.2")) -- "5.2"
-- print(version("Lua 5.2 for me")) -- "5.2"
-- print(version("5..2")) -- nil, "Not a valid version element: '5..2'"
--
-- -- strict parsing
-- print(version.strict("5.2")) -- "5.2"
-- print(version.strict("Lua 5.2 for me")) -- nil, "Not a valid version element: 'Lua 5.2 for me'"
-- print(version.strict("5..2")) -- nil, "Not a valid version element: '5..2'"
--
-- @copyright Kong Inc.
-- @author Thijs Schreijer
-- @license Apache 2.0
local table_insert = table.insert
local table_concat = table.concat
local math_max = math.max
-- Utility split function
local function split(str, pat)
local t = {}
local fpat = "(.-)" .. pat
local last_end = 1
local s, e, cap = str:find(fpat, 1)
while s do
if s ~= 1 or cap ~= "" then
table_insert(t,cap)
end
last_end = e + 1
s, e, cap = str:find(fpat, last_end)
end
if last_end <= #str then
cap = str:sub(last_end)
table_insert(t, cap)
end
return t
end
-- foreward declaration of constructor
local _new, _range, _set
-- Metatables for version, range and set
local mt_version
mt_version = {
__index = {
--- Matches a provider-version on a consumer-version based on the
-- semantic versioning specification.
-- The implementation does not support pre-release and/or build metadata,
-- only the major, minor, and patch levels are compared.
-- @function ver:semver
-- @param v Version (string or `version` object) as served by the provider
-- @return `true` or `false` whether the version matches, or `nil+err`
-- @usage local consumer = "1.2" -- consumer requested version
-- local provider = "1.5.2" -- provider served version
--
-- local compatible = version(consumer):semver(provider)
semver = function(self, v)
-- this function will be called once (in the meta table), it will set
-- the actual function on the version table itself
if self[1] == 0 then
-- major 0 is only compatible when equal
self.semver = function(self2, v2)
if getmetatable(v2) ~= mt_version then
local parsed, err = _new(v2, self2.strict)
if not parsed then return nil, err end
v2 = parsed
end
return self2 == v2
end
elseif self[4] then
-- more than 3 elements, cannot compare
self.semver = function()
return nil, "Version has too many elements (semver max 3)"
end
else
local semver_set = _set(self, self[1] + 1, self.strict):disallowed(self[1] + 1)
self.semver = function(_, v2)
return semver_set:matches(v2)
end
end
return self:semver(v)
end
},
__eq = function(a,b)
local l = math_max(#a, #b)
for i = 1, l do
if (a[i] or 0) ~= (b[i] or 0) then
return false
end
end
return true
end,
__lt = function(a,b)
if getmetatable(a) ~= mt_version or getmetatable(b) ~= mt_version then
local t = getmetatable(a) ~= mt_version and type(a) or type(b)
error("cannot compare a 'version' to a '" .. t .. "'", 2)
end
local l = math_max(#a, #b)
for i = 1, l do
if (a[i] or 0) < (b[i] or 0) then
return true
end
if (a[i] or 0) > (b[i] or 0) then
return false
end
end
return false
end,
__tostring = function(self)
return table_concat(self, ".")
end,
}
local mt_range = {
__index = {
--- Matches a version on a range.
-- @function range:matches
-- @param v Version (string or `version` object) to match
-- @return `true` or `false` whether the version matches the range, or `nil+err`
matches = function(self, v)
if getmetatable(v) ~= mt_version then
local parsed, err = _new(v, self.strict)
if not parsed then return nil, err end
v = parsed
end
return (v >= self.from) and (v <= self.to)
end,
},
__tostring = function(self)
local f, t = tostring(self.from), tostring(self.to)
if f == t then
return f
else
return f .. " to " .. t
end
end,
}
local mt_set = {
__index = {
--- Adds an ALLOWED range to the set.
-- @function set:allowed
-- @param v1 Version or range, if version, the FROM version in either string or `version` object format
-- @param v2 Version (optional), TO version in either string or `version` object format
-- @return The `set` object, to easy chain multiple allowed/disallowed ranges, or `nil+err`
allowed = function(self, v1, v2)
if getmetatable(v1) == mt_range then
assert (v2 == nil, "First parameter was a range, second must be nil.")
table_insert(self.ok, v1)
else
local r, err = _range(v1, v2, self.strict)
if not r then return nil, err end
table_insert(self.ok, r)
end
return self
end,
--- Adds a DISALLOWED range to the set.
-- @function set:disallowed
-- @param v1 Version or range, if version, the FROM version in either string or `version` object format
-- @param v2 Version (optional), TO version in either string or `version` object format
-- @return The `set` object, to easy chain multiple allowed/disallowed ranges, or `nil+err`
disallowed = function(self,v1, v2)
if getmetatable(v1) == mt_range then
assert (v2 == nil, "First parameter was a range, second must be nil.")
table_insert(self.nok, v1)
else
local r, err = _range(v1, v2, self.strict)
if not r then return nil, err end
table_insert(self.nok, r)
end
return self
end,
--- Matches a version against the set of allowed and disallowed versions.
--
-- NOTE: `disallowed` has a higher precedence, so a version that matches the `allowed` set,
-- but also the `disallowed` set, will return `false`.
-- @function set:matches
-- @param v1 Version to match (either string or `version` object).
-- @return `true` or `false` whether the version matches the set, or `nil+err`
matches = function(self, v)
if getmetatable(v) ~= mt_version then
local parsed, err = _new(v, self.strict)
if not parsed then return nil, err end
v = parsed
end
local success
for _, range in pairs(self.ok) do
if range:matches(v) then
success = true
break
end
end
if not success then
return false
end
for _, range in pairs(self.nok) do
if range:matches(v) then
return false
end
end
return true
end,
},
__tostring = function(self)
local ok, nok
if #self.ok == 1 then
ok = tostring(self.ok[1])
elseif #self.ok > 1 then
ok = tostring(self.ok[1])
for i = 2, #self.ok - 1 do
ok = ok .. ", " ..tostring(self.ok[i])
end
ok = ok .. ", and " .. tostring(self.ok[#self.ok])
end
if #self.nok == 1 then
nok = tostring(self.nok[1])
elseif #self.nok > 1 then
nok = tostring(self.nok[1])
for i = 2, #self.nok - 1 do
nok = nok .. ", " ..tostring(self.nok[i])
end
nok = nok .. ", and " .. tostring(self.nok[#self.nok])
end
if ok and nok then
return ok .. ", but not " .. nok
else
return ok
end
end,
}
_new = function(v, strict)
v = tostring(v)
if strict then
-- edge case: do not allow trailing dot
if v:sub(-1,-1) == "." then
return nil, "Not a valid version element: '"..tostring(v).."'"
end
else
local m = v:match("(%d[%d%.]*)")
if not m then
return nil, "Not a valid version element: '"..tostring(v).."'"
end
v = m
end
local t = split(v, "%.")
for i, s in ipairs(t) do
local n = tonumber(s)
if not n then
return nil, "Not a valid version element: '"..tostring(v).."'"
end
t[i] = n
end
t.strict = strict
return setmetatable(t, mt_version)
end
_range = function(v1,v2, strict)
local err
assert (v1 or v2, "At least one parameter is required")
v1 = v1 or "0"
v2 = v2 or v1
if getmetatable(v1) ~= mt_version then
v1, err = _new(v1, strict)
if not v1 then return nil, err end
end
if getmetatable(v2) ~= mt_version then
v2, err = _new(v2, strict)
if not v2 then return nil, err end
end
if v1 > v2 then
return nil, "FROM version must be less than or equal to the TO version"
end
return setmetatable({
from = v1,
to = v2,
strict = strict,
}, mt_range)
end
_set = function(v1, v2, strict)
return setmetatable({
ok = {},
nok = {},
strict = strict,
}, mt_set):allowed(v1, v2)
end
local make_module = function(strict)
return setmetatable({
--- Creates a new version object from a string.
-- The returned table will have
-- comparison operators, eg. LT, EQ, GT. For all comparisons, any missing numbers
-- will be assumed to be "0" on the least significant side of the version string.
--
-- Calling on the module table is a shortcut to `new`.
-- @param v String formatted as numbers separated by dots (no limit on number of elements).
-- @return `version` object, or `nil+err`
-- @usage local v = version.new("0.1")
-- -- is identical to
-- local v = version("0.1")
--
-- print(v) --> "0.1"
-- print(v[1]) --> 0
-- print(v[2]) --> 1
new = function(v) return _new(v, strict) end,
--- Creates a version range. A `range` object represents a range of versions.
-- @param v1 The FROM version of the range (string or `version` object). If `nil`, assumed to be 0.
-- @param v2 (optional) The TO version of the range (string or `version` object). Defaults to `v1`.
-- @return range object with `from` and `to` fields and `set:matches` method, or `nil+err`.
-- @usage local r = version.range("0.1"," 2.4")
--
-- print(v.from) --> "0.1"
-- print(v.to[1]) --> 2
-- print(v.to[2]) --> 4
range = function(v1,v2) return _range(v1, v2, strict) end,
--- Creates a version set.
-- A `set` is an object that contains a number of allowed and disallowed version `range` objects.
-- @param v1 initial version/range to allow, see `set:allowed` for parameter descriptions
-- @param v2 initial version/range to allow, see `set:allowed` for parameter descriptions
-- @return a `set` object, with `ok` and `nok` lists and a `set:matches` method, or `nil+err`
set = function(v1, v2) return _set(v1, v2, strict) end,
}, {
__call = function(self, ...)
return self.new(...)
end
})
end
local _M = make_module(false)
--- Similar module, but with stricter parsing rules.
-- `version.strict` is identical to the `version` module itself, but it requires
-- exact version strings, where as the regular parser will simply grab the
-- first sequence of numbers and dots from the string.
-- @field strict same module, but for stricter parsing.
_M.strict = make_module(true)
return _M