From 5d1cb5619ea720968e01ec9a63422b2cc30295ef Mon Sep 17 00:00:00 2001 From: Determinant Date: Sun, 24 May 2015 19:11:59 +0800 Subject: add utils.lua from Penlight --- pl/compat.lua | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 pl/compat.lua (limited to 'pl/compat.lua') diff --git a/pl/compat.lua b/pl/compat.lua new file mode 100644 index 0000000..7959ac3 --- /dev/null +++ b/pl/compat.lua @@ -0,0 +1,137 @@ +---------------- +--- Lua 5.1/5.2 compatibility +-- Ensures that `table.pack` and `package.searchpath` are available +-- for Lua 5.1 and LuaJIT. +-- The exported function `load` is Lua 5.2 compatible. +-- `compat.setfenv` and `compat.getfenv` are available for Lua 5.2, although +-- they are not always guaranteed to work. +-- @module pl.compat + +local compat = {} + +compat.lua51 = _VERSION == 'Lua 5.1' + +--- execute a shell command. +-- This is a compatibility function that returns the same for Lua 5.1 and Lua 5.2 +-- @param cmd a shell command +-- @return true if successful +-- @return actual return code +function compat.execute (cmd) + local res1,res2,res2 = os.execute(cmd) + if compat.lua51 then + return res1==0,res1 + else + return not not res1,res2 + end +end + +---------------- +-- Load Lua code as a text or binary chunk. +-- @param ld code string or loader +-- @param[opt] source name of chunk for errors +-- @param[opt] mode 'b', 't' or 'bt' +-- @param[opt] env environment to load the chunk in +-- @function compat.load + +--------------- +-- Get environment of a function. +-- With Lua 5.2, may return nil for a function with no global references! +-- Based on code by [Sergey Rozhenko](http://lua-users.org/lists/lua-l/2010-06/msg00313.html) +-- @param f a function or a call stack reference +-- @function compat.setfenv + +--------------- +-- Set environment of a function +-- @param f a function or a call stack reference +-- @param env a table that becomes the new environment of `f` +-- @function compat.setfenv + +if compat.lua51 then -- define Lua 5.2 style load() + if not tostring(assert):match 'builtin' then -- but LuaJIT's load _is_ compatible + local lua51_load = load + function compat.load(str,src,mode,env) + local chunk,err + if type(str) == 'string' then + if str:byte(1) == 27 and not (mode or 'bt'):find 'b' then + return nil,"attempt to load a binary chunk" + end + chunk,err = loadstring(str,src) + else + chunk,err = lua51_load(str,src) + end + if chunk and env then setfenv(chunk,env) end + return chunk,err + end + else + compat.load = load + end + compat.setfenv, compat.getfenv = setfenv, getfenv +else + compat.load = load + -- setfenv/getfenv replacements for Lua 5.2 + -- by Sergey Rozhenko + -- http://lua-users.org/lists/lua-l/2010-06/msg00313.html + -- Roberto Ierusalimschy notes that it is possible for getfenv to return nil + -- in the case of a function with no globals: + -- http://lua-users.org/lists/lua-l/2010-06/msg00315.html + function compat.setfenv(f, t) + f = (type(f) == 'function' and f or debug.getinfo(f + 1, 'f').func) + local name + local up = 0 + repeat + up = up + 1 + name = debug.getupvalue(f, up) + until name == '_ENV' or name == nil + if name then + debug.upvaluejoin(f, up, function() return name end, 1) -- use unique upvalue + debug.setupvalue(f, up, t) + end + if f ~= 0 then return f end + end + + function compat.getfenv(f) + local f = f or 0 + f = (type(f) == 'function' and f or debug.getinfo(f + 1, 'f').func) + local name, val + local up = 0 + repeat + up = up + 1 + name, val = debug.getupvalue(f, up) + until name == '_ENV' or name == nil + return val + end +end + +--- Lua 5.2 Functions Available for 5.1 +-- @section lua52 + +--- pack an argument list into a table. +-- @param ... any arguments +-- @return a table with field n set to the length +-- @return the length +-- @function table.pack +if not table.pack then + function table.pack (...) + return {n=select('#',...); ...} + end +end + +------ +-- return the full path where a Lua module name would be matched. +-- @param mod module name, possibly dotted +-- @param path a path in the same form as package.path or package.cpath +-- @see path.package_path +-- @function package.searchpath +if not package.searchpath then + local sep = package.config:sub(1,1) + function package.searchpath (mod,path) + mod = mod:gsub('%.',sep) + for m in path:gmatch('[^;]+') do + local nm = m:gsub('?',mod) + local f = io.open(nm,'r') + if f then f:close(); return nm end + end + end +end + +return compat -- cgit v1.2.3-70-g09d2