std.normalizeNormalize API differences between supported Lua implementations.
Respecting the values set in the std._debug settings module, inject
deterministic identically behaving cross-implementation low-level
functions into the callers environment.
Writing Lua libraries that target several Lua implementations can be a frustrating exercise in working around lots of small differences in APIs and semantics they share (or rename, or omit). normalize provides the means to simply access deterministic implementations of those APIs that have the the same semantics across all supported host Lua implementations. Each function is as thin and fast an implementation as is possible within that host Lua environment, evaluating to the Lua C implementation with no overhead where host semantics allow.
The core of this module is to transparently set the environment up with a single API (as opposed to requiring caching functions from a module table into module locals):
local _ENV = require 'std.normalize' { 'package', 'std.prototype', strict = 'std.strict', }
It is not yet complete, and in contrast to the kepler project lua-compat libraries, neither does it attempt to provide you with as nearly compatible an API as is possible relative to some specific Lua implementation - rather it provides a variation of the "lowest common denominator" that can be implemented relatively efficiently in the supported Lua implementations, all in pure Lua.
At the moment, only the functionality used by stdlib is implemented.
| argerror (name, i[, extramsg[, level=1]]) | Raise a bad argument error. |
| getfenv (fn) | Get a function or functor environment. |
| getmetamethod (x, n) | Return named metamethod, if callable, otherwise nil. |
| ipairs (t) | Iterate over elements of a sequence, until the first nil value. |
| len (x) | Deterministic, functional version of core Lua # operator. |
| load (ld, source) | Load a string or a function, just like Lua 5.2+. |
| pack (...) | Return a list of given arguments, with field n set to the length. |
| pairs (t) | Like Lua pairs iterator, but respect __pairs even in Lua 5.1. |
| rawlen (x) | Length of a string or table object without using any metamethod. |
| setfenv (fn, env) | Set a function or functor environment. |
| str (x) | Return a compact stringified representation of argument. |
| unpack (t[, i=1[, j=len(t)]]) | Either table.unpack in newer-, or unpack in older Lua implementations. |
| xpcall (f, errh, ...) | Support arguments to a protected function call, even on Lua 5.1. |
| math.tointeger (x) | Convert to an integer and return if possible, otherwise nil. |
| math.type (x) | Return 'integer', 'float' or nil according to argument type. |
| os.exit (status) | Exit the program. |
| package.searchpath (name, path[, sep='.'[, rep=`package.dirsep`]]) | Searches for a named file in a given path. |
| string.render (x, vfns[, roots]) | Low-level recursive data to string rendering. |
| table.keys (t) | Return an unordered list of all keys in a table. |
| table.merge (t[, u={}]) | Destructively merge keys and values from one table into another. |
| package | Package module constants for package.config substrings. |
| __call (env[, level=1]) | Normalize caller's lexical environment. |
| __index (name) | Lazy loading of normalize modules. |
| RenderFns | Table of functions for string.render. |
| RenderElem (x) | Type of function for uniquely stringifying rendered element. |
| RenderTerm (x) | Type of predicate function for terminal elements. |
| RenderSort (keys) | Type of function for sorting keys of a recursively rendered element. |
| RenderOpen (x) | Type of function to get string for before first element. |
| RenderClose (x) | Type of function te get string for after last element. |
| RenderPair (x, kp, vp, k, v, kstr, vstr, seqp) | Type of function to render a key value pair. |
| RenderSep (x, kp, vp, kn, vn, seqp) | Type of function to render a separator between pairs. |
level argument behaves just like the core error
function.
additional text to append to message inside
parentheses
(optional)
local function slurp(file) local h, err = input_handle(file) if h == nil then argerror('std.io.slurp', 1, err, 2) end ...
__call metamethod).
stack level, C or Lua function or functor
to act on
callers_environment = getfenv(1)
nil.
metamethod function, or nil if no
metamethod
normalize = getmetamethod(require 'std.normalize', '__call')
nil value.
Returns successive key-value pairs with integer keys starting at 1,
up to the index returned by the __len metamethod if any, or else
up to last non-nil value.
Unlike Lua 5.1, any __index metamethod is respected.
__ipairs metamethod is ignored!
t, u = {}, {}
for i, v in ipairs {1, 2, nil, 4} do t[i] = v end
assert(len(t) == 2)
for i, v in ipairs(pack(1, 2, nil, 4)) do u[i] = v end
assert(len(u) == 4)
# operator.
Respects __len metamethod (like Lua 5.2+), or else if there is
a __tostring metamethod return the length of the string it
returns. Otherwise, always return one less than the lowest
integer index with a nil value in x, where the # operator
implementation might return the size of the array part of a table.
x = {1, 2, 3, nil, 5}
--> 5 3
print(#x, len(x))
assert(load 'print "woo"')()
n set to the length.
The returned table also has a __len metamethod that returns n, so
ipairs and unpack behave sanely when there are nil valued elements.
packed list of ... values, with field n set to
number of tuple elements (including any explicit `nil` elements)
--> 5 len(pack(nil, 2, 5, nil, nil))
pairs iterator, but respect __pairs even in Lua 5.1.
for k, v in pairs {'a', b='c', foo=42} do process(k, v) end
--> 0 rawlen(setmetatable({}, {__len=function() return 42}))
stack level, C or Lua function or functor
to act on
function clearenv(fn) return setfenv(fn, {}) end
-- {baz,5,foo=bar} print(str{foo='bar','baz', 5})
table.unpack in newer-, or unpack in older Lua implementations.
local a, b, c = unpack(pack(nil, 2, nil)) assert(a == nil and b == 2 and c == nil)
error object handler callback if f raises
an error
false when f(...) raised an errortrue when f(...) succeeded
-- Use errh to get a backtrack after curses exits abnormally xpcall(main, errh, arg, opt)
nil.
nil otherwise
nil according to argument type.
To ensure the same behaviour on all host Lua implementations,
this function returns 'float' for integer-equivalent floating
values, even on Lua 5.3.
nil otherwise
exit(len(records.processed) > 0)
For each package.pathsep delimited template in the given path,
search for an readable file made by first substituting for sep
with package.dirsep, and then replacing any
package.pathmark with the result. The first such file, if any
is returned.
package.pathsep delimited list of full path templates
first template substitution that names a file
that can be opened in read mode
nilfunction printarray(x) return render(x, arrayvfns) end
--> {'key2', 1, 42, 2, 'key1'} keys{'a', 'b', key1=1, key2=2, [42]=3}
--> {'a', 'b', d='d'} merge({'a', 'b'}, {'c', d='d'})
package.config substrings.
ignore everything before this when building
`luaopen_` function name
Normalize caller's lexical environment.
Using 'std.strict' when available and selected, otherwise a (Lua 5.1 compatible) function to set the given environment.
With an empty table argument, the core (not-table) normalize
functions are loaded into the callers environment. For consistent
behaviour between supported host Lua implementations, the result
must always be assigned back to _ENV. Additional core modules
must be named to be loaded at all (i.e. no 'debug' table unless it
is explicitly listed in the argument table).
Additionally, external modules are loaded using require, with .
separators in the module name translated to nested tables in the
module environment. For example 'std.prototype' in the usage below
will add to the environment table the equivalent of:
local prototype = require 'std.prototype'
Alternatively, you can assign a loaded module symbol to a specific
environment table symbol with key=value syntax. For example the
the 'math.tointeger' from the usage below is equivalent to:
local int = require 'std.normalize.math'.tointeger
Compare this to loading the non-normalized implementation from the host Lua with a table entry such as:
int = require 'math'.tointeger,
Finally, explicit string assignment to ALLCAPS keys are not loaded from modules at all, but behave as a constant string assignment:
INT = 'math.tointeger',
stack level for setfenv, 1 means set
caller's environment
(default 1)
env with this module's functions merge id. Assign
back to `_ENV`
local _ENV = require 'std.normalize' { 'string', 'std.prototype', int = 'math.tointeger', }
the submodule that was loaded to satisfy the missing
`name`, otherwise `nil` if nothing was found
local version = require 'std.normalize'.version
return true for elements that should not be
recursed
return a string rendering of a key value pair
element
arrayvfns = {
elem = tostring,
term = function(x)
return type(x) ~= 'table' or getmetamethod(x, '__tostring')
end,
sort = function(keys)
local r = {}
for i = 1, #keys do
if type(keys[i]) == 'number' then r[#r + 1] = keys[i] end
end
return r
end,
open = function(_) return '[' end,
close = function(_) return ']' end,
pair = function(x, kp, vp, k, v, kstr, vstr, seqp)
return seqp and vstr or ''
end,
sep = function(x, kp, vp, kn, vn, seqp)
return seqp and kp ~= nil and kn ~= nil and ', ' or ''
end,
)
true for terminal elements that should be rendered
immediately
list of table keys, it's okay to mutate and return
this parameter
true if all keys so far have been a contiguous range of
integers
true if all keys so far have been a contiguous range of
integers
stringified rendering of separator between previous and
next pairs