2 --- Lua 5.1/5.2/5.3 compatibility.
3 -- Ensures that `table.pack` and `package.searchpath` are available
4 -- for Lua 5.1 and LuaJIT.
5 -- The exported function `load` is Lua 5.2 compatible.
6 -- `compat.setfenv` and `compat.getfenv` are available for Lua 5.2, although
7 -- they are not always guaranteed to work.
12 compat.lua51 = _VERSION == 'Lua 5.1'
14 local isJit = (tostring(assert):match('builtin') ~= nil)
16 -- 'goto' is a keyword when 52 compatibility is enabled in LuaJit
17 compat.jit52 = not loadstring("local goto = 1")
20 --- execute a shell command.
21 -- This is a compatibility function that returns the same for Lua 5.1 and Lua 5.2
22 -- @param cmd a shell command
23 -- @return true if successful
24 -- @return actual return code
25 function compat.execute (cmd)
26 local res1,_,res3 = os.execute(cmd)
27 if compat.lua51 and not compat.jit52 then
30 return not not res1,res3
35 -- Load Lua code as a text or binary chunk.
36 -- @param ld code string or loader
37 -- @param[opt] source name of chunk for errors
38 -- @param[opt] mode 'b', 't' or 'bt'
39 -- @param[opt] env environment to load the chunk in
40 -- @function compat.load
43 -- Get environment of a function.
44 -- With Lua 5.2, may return nil for a function with no global references!
45 -- Based on code by [Sergey Rozhenko](http://lua-users.org/lists/lua-l/2010-06/msg00313.html)
46 -- @param f a function or a call stack reference
47 -- @function compat.getfenv
50 -- Set environment of a function
51 -- @param f a function or a call stack reference
52 -- @param env a table that becomes the new environment of `f`
53 -- @function compat.setfenv
55 if compat.lua51 then -- define Lua 5.2 style load()
56 if not isJit then -- but LuaJIT's load _is_ compatible
57 local lua51_load = load
58 function compat.load(str,src,mode,env)
60 if type(str) == 'string' then
61 if str:byte(1) == 27 and not (mode or 'bt'):find 'b' then
62 return nil,"attempt to load a binary chunk"
64 chunk,err = loadstring(str,src)
66 chunk,err = lua51_load(str,src)
68 if chunk and env then setfenv(chunk,env) end
74 compat.setfenv, compat.getfenv = setfenv, getfenv
77 -- setfenv/getfenv replacements for Lua 5.2
79 -- http://lua-users.org/lists/lua-l/2010-06/msg00313.html
80 -- Roberto Ierusalimschy notes that it is possible for getfenv to return nil
81 -- in the case of a function with no globals:
82 -- http://lua-users.org/lists/lua-l/2010-06/msg00315.html
83 function compat.setfenv(f, t)
84 f = (type(f) == 'function' and f or debug.getinfo(f + 1, 'f').func)
89 name = debug.getupvalue(f, up)
90 until name == '_ENV' or name == nil
92 debug.upvaluejoin(f, up, function() return name end, 1) -- use unique upvalue
93 debug.setupvalue(f, up, t)
95 if f ~= 0 then return f end
98 function compat.getfenv(f)
100 f = (type(f) == 'function' and f or debug.getinfo(f + 1, 'f').func)
105 name, val = debug.getupvalue(f, up)
106 until name == '_ENV' or name == nil
111 --- Lua 5.2 Functions Available for 5.1
114 --- pack an argument list into a table.
115 -- @param ... any arguments
116 -- @return a table with field n set to the length
117 -- @return the length
118 -- @function table.pack
119 if not table.pack then
120 function table.pack (...)
121 return {n=select('#',...); ...}
126 -- return the full path where a Lua module name would be matched.
127 -- @param mod module name, possibly dotted
128 -- @param path a path in the same form as package.path or package.cpath
129 -- @see path.package_path
130 -- @function package.searchpath
131 if not package.searchpath then
132 local sep = package.config:sub(1,1)
133 function package.searchpath (mod,path)
134 mod = mod:gsub('%.',sep)
135 for m in path:gmatch('[^;]+') do
136 local nm = m:gsub('?',mod)
137 local f = io.open(nm,'r')
138 if f then f:close(); return nm end