aboutsummaryrefslogtreecommitdiff
path: root/compat53/init.lua
diff options
context:
space:
mode:
authorPhilipp Janda <siffiejoe@gmx.net>2015-04-25 21:07:05 +0200
committerPhilipp Janda <siffiejoe@gmx.net>2015-04-25 21:07:05 +0200
commit67dd52ab4ee97cf644ed4540df14c9619b50d0af (patch)
tree4e0ccbdb8054f8eff9213aedf397d7831148b6d5 /compat53/init.lua
parentaef3f24e32f6c50473b957c7fdd5ad707b543995 (diff)
downloadlua-compat-5.3-67dd52ab4ee97cf644ed4540df14c9619b50d0af.tar.gz
lua-compat-5.3-67dd52ab4ee97cf644ed4540df14c9619b50d0af.tar.bz2
lua-compat-5.3-67dd52ab4ee97cf644ed4540df14c9619b50d0af.zip
Refactor compat53 and compat53.module Lua modules.
The new compat53.module module contains only changes that don't affect other files, and it is supposed to be used in modules like this: local _ENV = require( "compat53.module" ) if setfenv then setfenv( 1, _ENV ) end compat53.module does not change string/file metatables, and it also doesn't support yielding from (x)pcall. The compat53 module copies all functions from compat53.module to the global environment, and additionally sets string/file metatables and implements yieldable (x)pcall.
Diffstat (limited to 'compat53/init.lua')
-rw-r--r--compat53/init.lua247
1 files changed, 234 insertions, 13 deletions
diff --git a/compat53/init.lua b/compat53/init.lua
index cdd5f34..e5f7692 100644
--- a/compat53/init.lua
+++ b/compat53/init.lua
@@ -1,7 +1,7 @@
1local _G, _VERSION, type, pairs, require = 1local _G, _VERSION, type, pairs, require =
2 _G, _VERSION, type, pairs, require 2 _G, _VERSION, type, pairs, require
3 3
4local M = require("compat53.base") 4local M = require("compat53.module")
5local lua_version = _VERSION:sub(-3) 5local lua_version = _VERSION:sub(-3)
6 6
7 7
@@ -9,9 +9,15 @@ local lua_version = _VERSION:sub(-3)
9if lua_version == "5.1" then 9if lua_version == "5.1" then
10 10
11 -- cache globals 11 -- cache globals
12 local error, rawset, select, setmetatable, type, unpack = 12 local error, pcall, rawset, select, setmetatable, tostring, type, unpack, xpcall =
13 error, rawset, select, setmetatable, type, unpack 13 error, pcall, rawset, select, setmetatable, tostring, type, unpack, xpcall
14 local debug, io, package, string = debug, io, package, string 14 local coroutine, debug, io, package, string =
15 coroutine, debug, io, package, string
16 local coroutine_create = coroutine.create
17 local coroutine_resume = coroutine.resume
18 local coroutine_running = coroutine.running
19 local coroutine_status = coroutine.status
20 local coroutine_yield = coroutine.yield
15 local io_type, io_stdout = io.type, io.stdout 21 local io_type, io_stdout = io.type, io.stdout
16 22
17 -- select the most powerful getmetatable function available 23 -- select the most powerful getmetatable function available
@@ -20,6 +26,8 @@ if lua_version == "5.1" then
20 26
21 -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag) 27 -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag)
22 local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ" 28 local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ"
29 local is_luajit52 = is_luajit and
30 #setmetatable({}, { __len = function() return 1 end }) == 1
23 31
24 32
25 -- make package.searchers available as an alias for package.loaders 33 -- make package.searchers available as an alias for package.loaders
@@ -80,24 +88,237 @@ if lua_version == "5.1" then
80 end 88 end
81 end -- not luajit 89 end -- not luajit
82 90
91
92 -- the (x)pcall implementations start a new coroutine internally
93 -- to allow yielding even in Lua 5.1. to allow for accurate
94 -- stack traces we keep track of the nested coroutine activations
95 -- in the weak tables below:
96 local weak_meta = { __mode = "kv" }
97 -- maps the internal pcall coroutines to the user coroutine that
98 -- *should* be running if pcall didn't use coroutines internally
99 local pcall_mainOf = setmetatable({}, weak_meta)
100 -- table that maps each running coroutine started by pcall to
101 -- the coroutine that resumed it (user coroutine *or* pcall
102 -- coroutine!)
103 local pcall_previous = setmetatable({}, weak_meta)
104 -- reverse of `pcall_mainOf`. maps a user coroutine to the
105 -- currently active pcall coroutine started within it
106 local pcall_callOf = setmetatable({}, weak_meta)
107 -- similar to `pcall_mainOf` but is used only while executing
108 -- the error handler of xpcall (thus no nesting is necessary!)
109 local xpcall_running = setmetatable({}, weak_meta)
110
111 -- handle debug functions
112 if type(debug) == "table" then
113 local debug_getinfo = debug.getinfo
114 local debug_traceback = debug.traceback
115
116 if not is_luajit then
117 local function calculate_trace_level(co, level)
118 if level ~= nil then
119 for out = 1, 1/0 do
120 local info = (co==nil) and debug_getinfo(out, "") or debug_getinfo(co, out, "")
121 if info == nil then
122 local max = out-1
123 if level <= max then
124 return level
125 end
126 return nil, level-max
127 end
128 end
129 end
130 return 1
131 end
132
133 local stack_pattern = "\nstack traceback:"
134 local stack_replace = ""
135 function debug.traceback(co, msg, level)
136 local lvl
137 local nilmsg
138 if type(co) ~= "thread" then
139 co, msg, level = coroutine_running(), co, msg
140 end
141 if msg == nil then
142 msg = ""
143 nilmsg = true
144 elseif type(msg) ~= "string" then
145 return msg
146 end
147 if co == nil then
148 msg = debug_traceback(msg, level or 1)
149 else
150 local xpco = xpcall_running[co]
151 if xpco ~= nil then
152 lvl, level = calculate_trace_level(xpco, level)
153 if lvl then
154 msg = debug_traceback(xpco, msg, lvl)
155 else
156 msg = msg..stack_pattern
157 end
158 lvl, level = calculate_trace_level(co, level)
159 if lvl then
160 local trace = debug_traceback(co, "", lvl)
161 msg = msg..trace:gsub(stack_pattern, stack_replace)
162 end
163 else
164 co = pcall_callOf[co] or co
165 lvl, level = calculate_trace_level(co, level)
166 if lvl then
167 msg = debug_traceback(co, msg, lvl)
168 else
169 msg = msg..stack_pattern
170 end
171 end
172 co = pcall_previous[co]
173 while co ~= nil do
174 lvl, level = calculate_trace_level(co, level)
175 if lvl then
176 local trace = debug_traceback(co, "", lvl)
177 msg = msg..trace:gsub(stack_pattern, stack_replace)
178 end
179 co = pcall_previous[co]
180 end
181 end
182 if nilmsg then
183 msg = msg:gsub("^\n", "")
184 end
185 msg = msg:gsub("\n\t%(tail call%): %?", "\000")
186 msg = msg:gsub("\n\t%.%.%.\n", "\001\n")
187 msg = msg:gsub("\n\t%.%.%.$", "\001")
188 msg = msg:gsub("(%z+)\001(%z+)", function(some, other)
189 return "\n\t(..."..#some+#other.."+ tail call(s)...)"
190 end)
191 msg = msg:gsub("\001(%z+)", function(zeros)
192 return "\n\t(..."..#zeros.."+ tail call(s)...)"
193 end)
194 msg = msg:gsub("(%z+)\001", function(zeros)
195 return "\n\t(..."..#zeros.."+ tail call(s)...)"
196 end)
197 msg = msg:gsub("%z+", function(zeros)
198 return "\n\t(..."..#zeros.." tail call(s)...)"
199 end)
200 msg = msg:gsub("\001", function(zeros)
201 return "\n\t..."
202 end)
203 return msg
204 end
205 end -- is not luajit
206 end -- debug table available
207
208
209 local main_coroutine = coroutine_create(function() end)
210
211 if not is_luajit52 then
212 function M.coroutine.running()
213 local co = coroutine_running()
214 if co then
215 return pcall_mainOf[co] or co, false
216 else
217 return main_coroutine, true
218 end
219 end
220 end
221
222 if not is_luajit then
223 function M.coroutine.resume(co, ...)
224 if co == main_coroutine then
225 return false, "cannot resume non-suspended coroutine"
226 else
227 return coroutine_resume(co, ...)
228 end
229 end
230
231 function M.coroutine.status(co)
232 local notmain = coroutine_running()
233 if co == main_coroutine then
234 return notmain and "normal" or "running"
235 else
236 return coroutine_status(co)
237 end
238 end
239
240 local function pcall_results(current, call, success, ...)
241 if coroutine_status(call) == "suspended" then
242 return pcall_results(current, call, coroutine_resume(call, coroutine_yield(...)))
243 end
244 if pcall_previous then
245 pcall_previous[call] = nil
246 local main = pcall_mainOf[call]
247 if main == current then current = nil end
248 pcall_callOf[main] = current
249 end
250 pcall_mainOf[call] = nil
251 return success, ...
252 end
253
254 local function pcall_exec(current, call, ...)
255 local main = pcall_mainOf[current] or current
256 pcall_mainOf[call] = main
257 if pcall_previous then
258 pcall_previous[call] = current
259 pcall_callOf[main] = call
260 end
261 return pcall_results(current, call, coroutine_resume(call, ...))
262 end
263
264 local coroutine_create52 = M.coroutine.create
265
266 local function pcall_coroutine(func)
267 if type(func) ~= "function" then
268 local callable = func
269 func = function (...) return callable(...) end
270 end
271 return coroutine_create52(func)
272 end
273
274 function _G.pcall(func, ...)
275 local current = coroutine_running()
276 if not current then return pcall(func, ...) end
277 return pcall_exec(current, pcall_coroutine(func), ...)
278 end
279
280 local function xpcall_catch(current, call, msgh, success, ...)
281 if not success then
282 xpcall_running[current] = call
283 local ok, result = pcall(msgh, ...)
284 xpcall_running[current] = nil
285 if not ok then
286 return false, "error in error handling ("..tostring(result)..")"
287 end
288 return false, result
289 end
290 return true, ...
291 end
292
293 function _G.xpcall(f, msgh, ...)
294 local current = coroutine_running()
295 if not current then
296 local args, n = { ... }, select('#', ...)
297 return xpcall(function() return f(unpack(args, 1, n)) end, msgh)
298 end
299 local call = pcall_coroutine(f)
300 return xpcall_catch(current, call, msgh, pcall_exec(current, call, ...))
301 end
302 end -- not luajit
303
83end -- lua == 5.1 304end -- lua == 5.1
84 305
85 306
86-- handle exporting to global scope 307-- handle exporting to global scope
87local function extend_table(from, to) 308local function extend_table(from, to)
88 for k,v in pairs(from) do 309 if from ~= to then
89 if type(v) == "table" and 310 for k,v in pairs(from) do
90 type(to[k]) == "table" and 311 if type(v) == "table" and
91 v ~= to[k] then 312 type(to[k]) == "table" and
92 extend_table(v, to[k]) 313 v ~= to[k] then
93 else 314 extend_table(v, to[k])
94 to[k] = v 315 else
316 to[k] = v
317 end
95 end 318 end
96 end 319 end
97end 320end
98 321
99extend_table(M, _G) 322extend_table(M, _G)
100 323
101return _G
102
103-- vi: set expandtab softtabstop=3 shiftwidth=3 : 324-- vi: set expandtab softtabstop=3 shiftwidth=3 :