diff options
Diffstat (limited to 'Data/BuiltIn/Libraries/lua-stdlib/init.lua')
-rw-r--r-- | Data/BuiltIn/Libraries/lua-stdlib/init.lua | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/Data/BuiltIn/Libraries/lua-stdlib/init.lua b/Data/BuiltIn/Libraries/lua-stdlib/init.lua new file mode 100644 index 0000000..732d41f --- /dev/null +++ b/Data/BuiltIn/Libraries/lua-stdlib/init.lua @@ -0,0 +1,389 @@ +--[[ + General Lua Libraries for Lua 5.1, 5.2 & 5.3 + Copyright (C) 2002-2018 stdlib authors +]] +--[[-- + Enhanced Lua core functions, and others. + + After requiring this module, simply referencing symbols in the submodule + hierarchy will load the necessary modules on demand. There are no + changes to any global symbols, or monkey patching of core module tables + and metatables. + + @todo Write a style guide(indenting/wrapping, capitalisation, + function and variable names); library functions should call + error, not die; OO vs non-OO(a thorny problem). + @todo pre-compile. + @corefunction std +]] + + +local _ = require 'std._base' + +local argscheck = _.typecheck and _.typecheck.argscheck +local compare = _.list.compare +local maxn = _.table.maxn +local split = _.string.split + +_ = nil + + +local _ENV = require 'std.normalize' { + format = 'string.format', + match = 'string.match', +} + + + +--[[ =============== ]]-- +--[[ Implementation. ]]-- +--[[ =============== ]]-- + + +local M + + +local function _assert(expect, fmt, arg1, ...) + local msg =(arg1 ~= nil) and format(fmt, arg1, ...) or fmt or '' + return expect or error(msg, 2) +end + + +local function elems(t) + -- capture pairs iterator initial state + local fn, istate, ctrl = pairs(t) + return function(state, _) + local v + ctrl, v = fn(state, ctrl) + if ctrl then + return v + end + end, istate, true -- wrapped initial state +end + + +local function eval(s) + return load('return ' .. s)() +end + + +local function ielems(t) + -- capture pairs iterator initial state + local fn, istate, ctrl = ipairs(t) + return function(state, _) + local v + ctrl, v = fn(state, ctrl) + if ctrl then + return v + end + end, istate, true -- wrapped initial state +end + + +local function npairs(t) + local m = getmetamethod(t, '__len') + local i, n = 0, m and m(t) or maxn(t) + return function(t) + i = i + 1 + if i <= n then + return i, t[i] + end + end, + t, i +end + + +local function ripairs(t) + local oob = 1 + while t[oob] ~= nil do + oob = oob + 1 + end + + return function(t, n) + n = n - 1 + if n > 0 then + return n, t[n] + end + end, t, oob +end + + +local function rnpairs(t) + local m = getmetamethod(t, '__len') + local oob =(m and m(t) or maxn(t)) + 1 + + return function(t, n) + n = n - 1 + if n > 0 then + return n, t[n] + end + end, t, oob +end + + +local vconvert = setmetatable({ + string = function(x) + return split(x, '%.') + end, + number = function(x) + return {x} + end, + table = function(x) + return x + end, +}, { + __call = function(self, x) + local fn = self[type(x)] or function() + return 0 + end + return fn(x) + end, +}) + + +local function vcompare(a, b) + return compare(vconvert(a), vconvert(b)) +end + + +local function _require(module, min, too_big, pattern) + pattern = pattern or '([%.%d]+)%D*$' + + local s, m = '', require(module) + if type(m) == 'table' then + s = tostring(m.version or m._VERSION or '') + end + local v = match(s, pattern) or 0 + if min then + _assert(vcompare(v, min) >= 0, "require '" .. module .. + "' with at least version " .. min .. ', but found version ' .. v) + end + if too_big then + _assert(vcompare(v, too_big) < 0, "require '" .. module .. + "' with version less than " .. too_big .. ', but found version ' .. v) + end + return m +end + + + +--[[ ================= ]]-- +--[[ Public Interface. ]]-- +--[[ ================= ]]-- + + +local function X(decl, fn) + return argscheck and argscheck('std.' .. decl, fn) or fn +end + +M = { + --- Release version string. + -- @field version + + + --- Core Functions + -- @section corefuncs + + --- Enhance core `assert` to also allow formatted arguments. + -- @function assert + -- @param expect expression, expected to be *truthy* + -- @string[opt=''] f format string + -- @param[opt] ... arguments to format + -- @return value of *expect*, if *truthy* + -- @usage + -- std.assert(expect == nil, '100% unexpected!') + -- std.assert(expect == 'expect', '%s the unexpected!', expect) + assert = X('assert(?any, ?string, [any...])', _assert), + + --- Evaluate a string as Lua code. + -- @function eval + -- @string s string of Lua code + -- @return result of evaluating `s` + -- @usage + -- --> 2 + -- std.eval 'math.min(2, 10)' + eval = X('eval(string)', eval), + + --- Return named metamethod, if any, otherwise `nil`. + -- The value found at the given key in the metatable of *x* must be a + -- function or have its own `__call` metamethod to qualify as a + -- callable. Any other value found at key *n* will cause this function + -- to return `nil`. + -- @function getmetamethod + -- @param x item to act on + -- @string n name of metamethod to lookup + -- @treturn callable|nil callable metamethod, or `nil` if no metamethod + -- @usage + -- clone = std.getmetamethod(std.object.prototype, '__call') + getmetamethod = X('getmetamethod(?any, string)', getmetamethod), + + + --- Module Functions + -- @section modulefuncs + + --- Enhance core `require` to assert version number compatibility. + -- By default match against the last substring of(dot-delimited) + -- digits in the module version string. + -- @function require + -- @string module module to require + -- @string[opt] min lowest acceptable version + -- @string[opt] too_big lowest version that is too big + -- @string[opt] pattern to match version in `module.version` or + -- `module._VERSION`(default: `'([%.%d]+)%D*$'`) + -- @usage + -- -- posix.version == 'posix library for Lua 5.2 / 32' + -- posix = require('posix', '29') + require = X('require(string, ?string, ?string, ?string)', _require), + + --- Iterator Functions + -- @section iteratorfuncs + + --- An iterator over all values of a table. + -- If *t* has a `__pairs` metamethod, use that to iterate. + -- @function elems + -- @tparam table t a table + -- @treturn function iterator function + -- @treturn table *t*, the table being iterated over + -- @return *key*, the previous iteration key + -- @see ielems + -- @see pairs + -- @usage + -- --> foo + -- --> bar + -- --> baz + -- --> 5 + -- std.functional.map(print, std.ielems, {'foo', 'bar', [4]='baz', d=5}) + elems = X('elems(table)', elems), + + --- An iterator over the integer keyed elements of a table. + -- + -- If *t* has a `__len` metamethod, iterate up to the index it + -- returns, otherwise up to the first `nil`. + -- + -- This function does **not** support the Lua 5.2 `__ipairs` metamethod. + -- @function ielems + -- @tparam table t a table + -- @treturn function iterator function + -- @treturn table *t*, the table being iterated over + -- @treturn int *index*, the previous iteration index + -- @see elems + -- @see ipairs + -- @usage + -- --> foo + -- --> bar + -- std.functional.map(print, std.ielems, {'foo', 'bar', [4]='baz', d=5}) + ielems = X('ielems(table)', ielems), + + --- An iterator over integer keyed pairs of a sequence. + -- + -- Like Lua 5.1 and 5.3, this iterator returns successive key-value + -- pairs with integer keys starting at 1, up to the first `nil` valued + -- pair. + -- + -- If there is a `_len` metamethod, keep iterating up to and including + -- that element, regardless of any intervening `nil` values. + -- + -- This function does **not** support the Lua 5.2 `__ipairs` metamethod. + -- @function ipairs + -- @tparam table t a table + -- @treturn function iterator function + -- @treturn table *t*, the table being iterated over + -- @treturn int *index*, the previous iteration index + -- @see ielems + -- @see npairs + -- @see pairs + -- @usage + -- --> 1 foo + -- --> 2 bar + -- std.functional.map(print, std.ipairs, {'foo', 'bar', [4]='baz', d=5}) + ipairs = X('ipairs(table)', ipairs), + + --- Ordered iterator for integer keyed values. + -- Like ipairs, but does not stop until the __len or maxn of *t*. + -- @function npairs + -- @tparam table t a table + -- @treturn function iterator function + -- @treturn table t + -- @see ipairs + -- @see rnpairs + -- @usage + -- --> 1 foo + -- --> 2 bar + -- --> 3 nil + -- --> 4 baz + -- std.functional.map(print, std.npairs, {'foo', 'bar', [4]='baz', d=5}) + npairs = X('npairs(table)', npairs), + + --- Enhance core `pairs` to respect `__pairs` even in Lua 5.1. + -- @function pairs + -- @tparam table t a table + -- @treturn function iterator function + -- @treturn table *t*, the table being iterated over + -- @return *key*, the previous iteration key + -- @see elems + -- @see ipairs + -- @usage + -- --> 1 foo + -- --> 2 bar + -- --> 4 baz + -- --> d 5 + -- std.functional.map(print, std.pairs, {'foo', 'bar', [4]='baz', d=5}) + pairs = X('pairs(table)', pairs), + + --- An iterator like ipairs, but in reverse. + -- Apart from the order of the elements returned, this function follows + -- the same rules as @{ipairs} for determining first and last elements. + -- @function ripairs + -- @tparam table t any table + -- @treturn function iterator function + -- @treturn table *t* + -- @treturn number `#t + 1` + -- @see ipairs + -- @see rnpairs + -- @usage + -- --> 2 bar + -- --> 1 foo + -- std.functional.map(print, std.ripairs, {'foo', 'bar', [4]='baz', d=5}) + ripairs = X('ripairs(table)', ripairs), + + --- An iterator like npairs, but in reverse. + -- Apart from the order of the elements returned, this function follows + -- the same rules as @{npairs} for determining first and last elements. + -- @function rnpairs + -- @tparam table t a table + -- @treturn function iterator function + -- @treturn table t + -- @see npairs + -- @see ripairs + -- @usage + -- --> 4 baz + -- --> 3 nil + -- --> 2 bar + -- --> 1 foo + -- std.functional.map(print, std.rnpairs, {'foo', 'bar', [4]='baz', d=5}) + rnpairs = X('rnpairs(table)', rnpairs), +} + + +--- Metamethods +-- @section Metamethods + +return setmetatable(M, { + --- Lazy loading of stdlib modules. + -- Don't load everything on initial startup, wait until first attempt + -- to access a submodule, and then load it on demand. + -- @function __index + -- @string name submodule name + -- @treturn table|nil the submodule that was loaded to satisfy the missing + -- `name`, otherwise `nil` if nothing was found + -- @usage + -- local std = require 'std' + -- local Object = std.object.prototype + __index = function(self, name) + local ok, t = pcall(require, 'std.' .. name) + if ok then + rawset(self, name, t) + return t + end + end, +}) |