summaryrefslogtreecommitdiff
path: root/pl/compat.lua
diff options
context:
space:
mode:
authorDeterminant <[email protected]>2015-05-24 19:11:59 +0800
committerDeterminant <[email protected]>2015-05-24 19:11:59 +0800
commit5d1cb5619ea720968e01ec9a63422b2cc30295ef (patch)
treeebd4476e3b30bb2079a845b4797c54e6ddb118a3 /pl/compat.lua
parent39e1834c449a55a44e95f2cfb6b24887fd3cec70 (diff)
add utils.lua from Penlight
Diffstat (limited to 'pl/compat.lua')
-rw-r--r--pl/compat.lua137
1 files changed, 137 insertions, 0 deletions
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