aboutsummaryrefslogtreecommitdiff
path: root/compat53/init.lua
diff options
context:
space:
mode:
authorPhilipp Janda <siffiejoe@gmx.net>2015-04-29 12:26:34 +0200
committerPhilipp Janda <siffiejoe@gmx.net>2015-04-29 12:26:34 +0200
commitc87038c1f3a6d3a21d14d6db1affbf879a25386a (patch)
tree0bbdb4925e1c47185b32f5e678a1265b80e69862 /compat53/init.lua
parentec5331cb94f9100fe4cf26d1ea215dd66e8e185c (diff)
parent17fdace5c04486db3470fe7022aee7eac8efc3af (diff)
downloadlua-compat-5.3-c87038c1f3a6d3a21d14d6db1affbf879a25386a.tar.gz
lua-compat-5.3-c87038c1f3a6d3a21d14d6db1affbf879a25386a.tar.bz2
lua-compat-5.3-c87038c1f3a6d3a21d14d6db1affbf879a25386a.zip
Merge branch 'isolated'
Conflicts: README.md
Diffstat (limited to 'compat53/init.lua')
-rw-r--r--compat53/init.lua324
1 files changed, 324 insertions, 0 deletions
diff --git a/compat53/init.lua b/compat53/init.lua
new file mode 100644
index 0000000..31085be
--- /dev/null
+++ b/compat53/init.lua
@@ -0,0 +1,324 @@
1local _G, _VERSION, type, pairs, require =
2 _G, _VERSION, type, pairs, require
3
4local M = require("compat53.module")
5local lua_version = _VERSION:sub(-3)
6
7
8-- apply other global effects
9if lua_version == "5.1" then
10
11 -- cache globals
12 local error, pcall, rawset, select, setmetatable, tostring, unpack, xpcall =
13 error, pcall, rawset, select, setmetatable, tostring, unpack, xpcall
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
21 local io_type, io_stdout = io.type, io.stdout
22
23 -- select the most powerful getmetatable function available
24 local gmt = type(debug) == "table" and debug.getmetatable or
25 getmetatable or function() return false end
26
27 -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag)
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
31
32
33 -- make package.searchers available as an alias for package.loaders
34 local p_index = { searchers = package.loaders }
35 setmetatable(package, {
36 __index = p_index,
37 __newindex = function(p, k, v)
38 if k == "searchers" then
39 rawset(p, "loaders", v)
40 p_index.searchers = v
41 else
42 rawset(p, k, v)
43 end
44 end
45 })
46
47
48 if not is_luajit then
49 local function helper(st, var_1, ...)
50 if var_1 == nil then
51 if (...) ~= nil then
52 error((...), 2)
53 end
54 end
55 return var_1, ...
56 end
57
58 local function lines_iterator(st)
59 return helper(st, st.f:read(unpack(st, 1, st.n)))
60 end
61
62 local valid_format = { ["*l"] = true, ["*n"] = true, ["*a"] = true }
63
64 local file_meta = gmt(io_stdout)
65 if type(file_meta) == "table" and type(file_meta.__index) == "table" then
66 local file_write = file_meta.__index.write
67 file_meta.__index.write = function(self, ...)
68 local res, msg, errno = file_write(self, ...)
69 if res then
70 return self
71 else
72 return nil, msg, errno
73 end
74 end
75
76 file_meta.__index.lines = function(self, ...)
77 if io_type(self) == "closed file" then
78 error("attempt to use a closed file", 2)
79 end
80 local st = { f=self, n=select('#', ...), ... }
81 for i = 1, st.n do
82 if type(st[i]) ~= "number" and not valid_format[st[i]] then
83 error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2)
84 end
85 end
86 return lines_iterator, st
87 end
88 end
89 end -- not luajit
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 M.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 M.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
304end -- lua == 5.1
305
306
307-- handle exporting to global scope
308local function extend_table(from, to)
309 if from ~= to then
310 for k,v in pairs(from) do
311 if type(v) == "table" and
312 type(to[k]) == "table" and
313 v ~= to[k] then
314 extend_table(v, to[k])
315 else
316 to[k] = v
317 end
318 end
319 end
320end
321
322extend_table(M, _G)
323
324-- vi: set expandtab softtabstop=3 shiftwidth=3 :