aboutsummaryrefslogtreecommitdiff
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
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
-rw-r--r--README.md18
-rw-r--r--compat53/init.lua324
-rw-r--r--compat53/module.lua (renamed from compat53.lua)470
-rwxr-xr-xtests/test.lua130
4 files changed, 559 insertions, 383 deletions
diff --git a/README.md b/README.md
index 8f45ccb..93bc4c8 100644
--- a/README.md
+++ b/README.md
@@ -42,6 +42,22 @@ string packing modules automatically. If unsuccessful, pure Lua
42versions of the new `table` functions are used as a fallback, and 42versions of the new `table` functions are used as a fallback, and
43[Roberto's struct library][1] is tried for string packing. 43[Roberto's struct library][1] is tried for string packing.
44 44
45#### Lua submodules
46
47```lua
48local _ENV = require("compat53.module")
49if setfenv then setfenv(1, _ENV) end
50```
51
52The `compat53.module` module does not modify the global environment,
53and so it is safe to use in modules without affecting other Lua files.
54It is supposed to be set as the current environment (see above), i.e.
55cherry picking individual functions from this module is expressly
56*not* supported!). Not all features are available when using this
57module (e.g. yieldable (x)pcall support, string/file methods, etc.),
58so it is recommended to use plain `require("compat53")` whenever
59possible.
60
45### C code 61### C code
46 62
47There are two ways of adding the C API compatibility functions/macros to 63There are two ways of adding the C API compatibility functions/macros to
@@ -67,7 +83,7 @@ your project:
67 5.3 sources or from the `struct` module. (`struct` is not 100% 83 5.3 sources or from the `struct` module. (`struct` is not 100%
68 compatible to Lua 5.3's string packing!) (See [here][4]) 84 compatible to Lua 5.3's string packing!) (See [here][4])
69* `math.maxinteger` and `math.mininteger`, `math.tointeger`, `math.type`, 85* `math.maxinteger` and `math.mininteger`, `math.tointeger`, `math.type`,
70 and `math.ult` (See [here][5]) 86 and `math.ult` (see [here][5])
71* `ipairs` respects `__index` metamethod 87* `ipairs` respects `__index` metamethod
72* `table.move` 88* `table.move`
73* `table` library respects metamethods 89* `table` library respects metamethods
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 :
diff --git a/compat53.lua b/compat53/module.lua
index 919ab33..0dd0317 100644
--- a/compat53.lua
+++ b/compat53/module.lua
@@ -1,8 +1,31 @@
1local _G, _VERSION = _G, _VERSION
1local lua_version = _VERSION:sub(-3) 2local lua_version = _VERSION:sub(-3)
2 3
4
5local M = _G
6
3if lua_version < "5.3" then 7if lua_version < "5.3" then
4 -- local aliases for commonly used functions 8
5 local type, select, error = type, select, error 9 -- cache globals in upvalues
10 local error, ipairs, pairs, pcall, require, select, setmetatable, type =
11 error, ipairs, pairs, pcall, require, select, setmetatable, type
12 local debug, math, package, string, table =
13 debug, math, package, string, table
14
15 -- create module table
16 M = {}
17 local M_meta = {
18 __index = _G,
19 -- __newindex is set at the end
20 }
21 setmetatable(M, M_meta)
22
23 -- create subtables
24 M.math = setmetatable({}, { __index = math })
25 M.string = setmetatable({}, { __index = string })
26 M.table = setmetatable({}, { __index = table })
27 M.utf8 = {}
28
6 29
7 -- select the most powerful getmetatable function available 30 -- select the most powerful getmetatable function available
8 local gmt = type(debug) == "table" and debug.getmetatable or 31 local gmt = type(debug) == "table" and debug.getmetatable or
@@ -29,11 +52,13 @@ if lua_version < "5.3" then
29 -- load utf8 library 52 -- load utf8 library
30 local utf8_ok, utf8lib = pcall(require, "compat53.utf8") 53 local utf8_ok, utf8lib = pcall(require, "compat53.utf8")
31 if utf8_ok then 54 if utf8_ok then
32 utf8 = utf8lib
33 package.loaded["utf8"] = utf8lib
34 if lua_version == "5.1" then 55 if lua_version == "5.1" then
35 utf8lib.charpattern = "[%z\1-\127\194-\244][\128-\191]*" 56 utf8lib.charpattern = "[%z\1-\127\194-\244][\128-\191]*"
36 end 57 end
58 for k,v in pairs(utf8lib) do
59 M.utf8[k] = v
60 end
61 package.loaded["utf8"] = M.utf8
37 end 62 end
38 63
39 64
@@ -41,7 +66,7 @@ if lua_version < "5.3" then
41 local table_ok, tablib = pcall(require, "compat53.table") 66 local table_ok, tablib = pcall(require, "compat53.table")
42 if table_ok then 67 if table_ok then
43 for k,v in pairs(tablib) do 68 for k,v in pairs(tablib) do
44 table[k] = v 69 M.table[k] = v
45 end 70 end
46 end 71 end
47 72
@@ -50,7 +75,7 @@ if lua_version < "5.3" then
50 local str_ok, strlib = pcall(require, "compat53.string") 75 local str_ok, strlib = pcall(require, "compat53.string")
51 if str_ok then 76 if str_ok then
52 for k,v in pairs(strlib) do 77 for k,v in pairs(strlib) do
53 string[k] = v 78 M.string[k] = v
54 end 79 end
55 end 80 end
56 81
@@ -60,9 +85,9 @@ if lua_version < "5.3" then
60 if not str_ok then 85 if not str_ok then
61 local struct_ok, struct = pcall(require, "struct") 86 local struct_ok, struct = pcall(require, "struct")
62 if struct_ok then 87 if struct_ok then
63 string.pack = struct.pack 88 M.string.pack = struct.pack
64 string.packsize = struct.size 89 M.string.packsize = struct.size
65 string.unpack = struct.unpack 90 M.string.unpack = struct.unpack
66 end 91 end
67 end 92 end
68 93
@@ -81,17 +106,17 @@ if lua_version < "5.3" then
81 maxint = maxint 106 maxint = maxint
82 minint = -maxint 107 minint = -maxint
83 end 108 end
84 math.maxinteger = maxint 109 M.math.maxinteger = maxint
85 math.mininteger = minint 110 M.math.mininteger = minint
86 111
87 function math.tointeger(n) 112 function M.math.tointeger(n)
88 if type(n) == "number" and n <= maxint and n >= minint and n % 1 == 0 then 113 if type(n) == "number" and n <= maxint and n >= minint and n % 1 == 0 then
89 return n 114 return n
90 end 115 end
91 return nil 116 return nil
92 end 117 end
93 118
94 function math.type(n) 119 function M.math.type(n)
95 if type(n) == "number" then 120 if type(n) == "number" then
96 if n <= maxint and n >= minint and n % 1 == 0 then 121 if n <= maxint and n >= minint and n % 1 == 0 then
97 return "integer" 122 return "integer"
@@ -116,7 +141,7 @@ if lua_version < "5.3" then
116 end 141 end
117 end 142 end
118 143
119 function math.ult(m, n) 144 function M.math.ult(m, n)
120 m = checkinteger(m, "1", "math.ult") 145 m = checkinteger(m, "1", "math.ult")
121 n = checkinteger(n, "2", "math.ult") 146 n = checkinteger(n, "2", "math.ult")
122 if m >= 0 and n < 0 then 147 if m >= 0 and n < 0 then
@@ -132,7 +157,6 @@ if lua_version < "5.3" then
132 157
133 -- ipairs should respect __index metamethod 158 -- ipairs should respect __index metamethod
134 do 159 do
135 local _ipairs = ipairs
136 local function ipairs_iterator(st, var) 160 local function ipairs_iterator(st, var)
137 var = var + 1 161 var = var + 1
138 local val = st[var] 162 local val = st[var]
@@ -140,11 +164,11 @@ if lua_version < "5.3" then
140 return var, st[var] 164 return var, st[var]
141 end 165 end
142 end 166 end
143 function ipairs(t) 167 function M.ipairs(t)
144 if gmt(t) ~= nil then -- t has metatable 168 if gmt(t) ~= nil then -- t has metatable
145 return ipairs_iterator, t, 0 169 return ipairs_iterator, t, 0
146 else 170 else
147 return _ipairs(t) 171 return ipairs(t)
148 end 172 end
149 end 173 end
150 end 174 end
@@ -153,7 +177,12 @@ if lua_version < "5.3" then
153 -- update table library (if C module not available) 177 -- update table library (if C module not available)
154 if not table_ok then 178 if not table_ok then
155 local table_concat = table.concat 179 local table_concat = table.concat
156 function table.concat(list, sep, i, j) 180 local table_insert = table.insert
181 local table_remove = table.remove
182 local table_sort = table.sort
183 local table_unpack = lua_version == "5.1" and unpack or table.unpack
184
185 function M.table.concat(list, sep, i, j)
157 local mt = gmt(list) 186 local mt = gmt(list)
158 if type(mt) == "table" and type(mt.__len) == "function" then 187 if type(mt) == "table" and type(mt.__len) == "function" then
159 local src = list 188 local src = list
@@ -165,8 +194,7 @@ if lua_version < "5.3" then
165 return table_concat(list, sep, i, j) 194 return table_concat(list, sep, i, j)
166 end 195 end
167 196
168 local table_insert = table.insert 197 function M.table.insert(list, ...)
169 function table.insert(list, ...)
170 local mt = gmt(list) 198 local mt = gmt(list)
171 local has_mt = type(mt) == "table" 199 local has_mt = type(mt) == "table"
172 local has_len = has_mt and type(mt.__len) == "function" 200 local has_len = has_mt and type(mt.__len) == "function"
@@ -191,7 +219,7 @@ if lua_version < "5.3" then
191 end 219 end
192 end 220 end
193 221
194 function table.move(a1, f, e, t, a2) 222 function M.table.move(a1, f, e, t, a2)
195 a2 = a2 or a1 223 a2 = a2 or a1
196 f = checkinteger(f, "2", "table.move") 224 f = checkinteger(f, "2", "table.move")
197 argcheck(f > 0, "2", "table.move", 225 argcheck(f > 0, "2", "table.move",
@@ -208,8 +236,7 @@ if lua_version < "5.3" then
208 return a2 236 return a2
209 end 237 end
210 238
211 local table_remove = table.remove 239 function M.table.remove(list, pos)
212 function table.remove(list, pos)
213 local mt = gmt(list) 240 local mt = gmt(list)
214 local has_mt = type(mt) == "table" 241 local has_mt = type(mt) == "table"
215 local has_len = has_mt and type(mt.__len) == "function" 242 local has_len = has_mt and type(mt.__len) == "function"
@@ -282,8 +309,7 @@ if lua_version < "5.3" then
282 end 309 end
283 end 310 end
284 311
285 local table_sort = table.sort 312 function M.table.sort(list, cmp)
286 function table.sort(list, cmp)
287 local mt = gmt(list) 313 local mt = gmt(list)
288 local has_mt = type(mt) == "table" 314 local has_mt = type(mt) == "table"
289 local has_len = has_mt and type(mt.__len) == "function" 315 local has_len = has_mt and type(mt.__len) == "function"
@@ -297,7 +323,6 @@ if lua_version < "5.3" then
297 end 323 end
298 end 324 end
299 325
300 local table_unpack = lua_version == "5.1" and unpack or table.unpack
301 local function unpack_helper(list, i, j, ...) 326 local function unpack_helper(list, i, j, ...)
302 if j < i then 327 if j < i then
303 return ... 328 return ...
@@ -305,7 +330,7 @@ if lua_version < "5.3" then
305 return unpack_helper(list, i, j-1, list[j], ...) 330 return unpack_helper(list, i, j-1, list[j], ...)
306 end 331 end
307 end 332 end
308 function table.unpack(list, i, j) 333 function M.table.unpack(list, i, j)
309 local mt = gmt(list) 334 local mt = gmt(list)
310 local has_mt = type(mt) == "table" 335 local has_mt = type(mt) == "table"
311 local has_len = has_mt and type(mt.__len) == "function" 336 local has_len = has_mt and type(mt.__len) == "function"
@@ -319,7 +344,6 @@ if lua_version < "5.3" then
319 end -- update table library 344 end -- update table library
320 345
321 346
322
323 -- bring Lua 5.1 (and LuaJIT) up to speed with Lua 5.2 347 -- bring Lua 5.1 (and LuaJIT) up to speed with Lua 5.2
324 if lua_version == "5.1" then 348 if lua_version == "5.1" then
325 -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag) 349 -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag)
@@ -327,31 +351,45 @@ if lua_version < "5.3" then
327 local is_luajit52 = is_luajit and 351 local is_luajit52 = is_luajit and
328 #setmetatable({}, { __len = function() return 1 end }) == 1 352 #setmetatable({}, { __len = function() return 1 end }) == 1
329 353
330 354 -- cache globals in upvalues
331 -- the (x)pcall implementations start a new coroutine internally 355 local load, loadfile, loadstring, setfenv, unpack, xpcall =
332 -- to allow yielding even in Lua 5.1. to allow for accurate 356 load, loadfile, loadstring, setfenv, unpack, xpcall
333 -- stack traces we keep track of the nested coroutine activations 357 local coroutine, io, os = coroutine, io, os
334 -- in the weak tables below: 358 local coroutine_create = coroutine.create
335 local weak_meta = { __mode = "kv" } 359 local coroutine_resume = coroutine.resume
336 -- table that maps each running coroutine started by pcall to
337 -- the coroutine that resumed it (user coroutine *or* pcall
338 -- coroutine!)
339 local pcall_previous = setmetatable({}, weak_meta)
340 -- reverse of `pcall_mainOf`. maps a user coroutine to the
341 -- currently active pcall coroutine started within it
342 local pcall_callOf = setmetatable({}, weak_meta)
343 -- similar to `pcall_mainOf` but is used only while executing
344 -- the error handler of xpcall (thus no nesting is necessary!)
345 local xpcall_running = setmetatable({}, weak_meta)
346 local coroutine_running = coroutine.running 360 local coroutine_running = coroutine.running
361 local coroutine_status = coroutine.status
362 local coroutine_yield = coroutine.yield
363 local io_input = io.input
364 local io_open = io.open
365 local io_output = io.output
366 local io_write = io.write
367 local math_log = math.log
368 local os_execute = os.execute
369 local string_find = string.find
370 local string_format = string.format
371 local string_gmatch = string.gmatch
372 local string_gsub = string.gsub
373 local string_match = string.match
374 local string_rep = string.rep
375 local table_concat = table.concat
376
377 -- create subtables
378 M.coroutine = setmetatable({}, { __index = coroutine })
379 M.io = setmetatable({}, { __index = io })
380 M.os = setmetatable({}, { __index = os })
381 M.package = setmetatable({}, { __index = package })
347 382
348 -- handle debug functions 383 -- handle debug functions
349 if type(debug) == "table" then 384 if type(debug) == "table" then
385 local debug_setfenv = debug.setfenv
386 local debug_getfenv = debug.getfenv
387 local debug_setmetatable = debug.setmetatable
388
389 M.debug = setmetatable({}, { __index = debug })
350 390
351 if not is_luajit52 then 391 if not is_luajit52 then
352 local _G, package = _G, package 392 function M.debug.setuservalue(obj, value)
353 local debug_setfenv = debug.setfenv
354 function debug.setuservalue(obj, value)
355 if type(obj) ~= "userdata" then 393 if type(obj) ~= "userdata" then
356 error("bad argument #1 to 'setuservalue' (userdata expected, got ".. 394 error("bad argument #1 to 'setuservalue' (userdata expected, got "..
357 type(obj)..")", 2) 395 type(obj)..")", 2)
@@ -364,8 +402,7 @@ if lua_version < "5.3" then
364 return debug_setfenv(obj, value) 402 return debug_setfenv(obj, value)
365 end 403 end
366 404
367 local debug_getfenv = debug.getfenv 405 function M.debug.getuservalue(obj)
368 function debug.getuservalue(obj)
369 if type(obj) ~= "userdata" then 406 if type(obj) ~= "userdata" then
370 return nil 407 return nil
371 else 408 else
@@ -377,116 +414,21 @@ if lua_version < "5.3" then
377 end 414 end
378 end 415 end
379 416
380 local debug_setmetatable = debug.setmetatable 417 function M.debug.setmetatable(value, tab)
381 function debug.setmetatable(value, tab)
382 debug_setmetatable(value, tab) 418 debug_setmetatable(value, tab)
383 return value 419 return value
384 end 420 end
385 end -- not luajit with compat52 enabled 421 end -- not luajit with compat52 enabled
386
387 if not is_luajit then
388 local debug_getinfo = debug.getinfo
389 local function calculate_trace_level(co, level)
390 if level ~= nil then
391 for out = 1, 1/0 do
392 local info = (co==nil) and debug_getinfo(out, "") or debug_getinfo(co, out, "")
393 if info == nil then
394 local max = out-1
395 if level <= max then
396 return level
397 end
398 return nil, level-max
399 end
400 end
401 end
402 return 1
403 end
404
405 local stack_pattern = "\nstack traceback:"
406 local stack_replace = ""
407 local debug_traceback = debug.traceback
408 function debug.traceback(co, msg, level)
409 local lvl
410 local nilmsg
411 if type(co) ~= "thread" then
412 co, msg, level = coroutine_running(), co, msg
413 end
414 if msg == nil then
415 msg = ""
416 nilmsg = true
417 elseif type(msg) ~= "string" then
418 return msg
419 end
420 if co == nil then
421 msg = debug_traceback(msg, level or 1)
422 else
423 local xpco = xpcall_running[co]
424 if xpco ~= nil then
425 lvl, level = calculate_trace_level(xpco, level)
426 if lvl then
427 msg = debug_traceback(xpco, msg, lvl)
428 else
429 msg = msg..stack_pattern
430 end
431 lvl, level = calculate_trace_level(co, level)
432 if lvl then
433 local trace = debug_traceback(co, "", lvl)
434 msg = msg..trace:gsub(stack_pattern, stack_replace)
435 end
436 else
437 co = pcall_callOf[co] or co
438 lvl, level = calculate_trace_level(co, level)
439 if lvl then
440 msg = debug_traceback(co, msg, lvl)
441 else
442 msg = msg..stack_pattern
443 end
444 end
445 co = pcall_previous[co]
446 while co ~= nil do
447 lvl, level = calculate_trace_level(co, level)
448 if lvl then
449 local trace = debug_traceback(co, "", lvl)
450 msg = msg..trace:gsub(stack_pattern, stack_replace)
451 end
452 co = pcall_previous[co]
453 end
454 end
455 if nilmsg then
456 msg = msg:gsub("^\n", "")
457 end
458 msg = msg:gsub("\n\t%(tail call%): %?", "\000")
459 msg = msg:gsub("\n\t%.%.%.\n", "\001\n")
460 msg = msg:gsub("\n\t%.%.%.$", "\001")
461 msg = msg:gsub("(%z+)\001(%z+)", function(some, other)
462 return "\n\t(..."..#some+#other.."+ tail call(s)...)"
463 end)
464 msg = msg:gsub("\001(%z+)", function(zeros)
465 return "\n\t(..."..#zeros.."+ tail call(s)...)"
466 end)
467 msg = msg:gsub("(%z+)\001", function(zeros)
468 return "\n\t(..."..#zeros.."+ tail call(s)...)"
469 end)
470 msg = msg:gsub("%z+", function(zeros)
471 return "\n\t(..."..#zeros.." tail call(s)...)"
472 end)
473 msg = msg:gsub("\001", function(zeros)
474 return "\n\t..."
475 end)
476 return msg
477 end
478 end -- is not luajit
479 end -- debug table available 422 end -- debug table available
480 423
481 424
482 if not is_luajit52 then 425 if not is_luajit52 then
483 local _pairs = pairs 426 function M.pairs(t)
484 function pairs(t)
485 local mt = gmt(t) 427 local mt = gmt(t)
486 if type(mt) == "table" and type(mt.__pairs) == "function" then 428 if type(mt) == "table" and type(mt.__pairs) == "function" then
487 return mt.__pairs(t) 429 return mt.__pairs(t)
488 else 430 else
489 return _pairs(t) 431 return pairs(t)
490 end 432 end
491 end 433 end
492 end 434 end
@@ -506,9 +448,7 @@ if lua_version < "5.3" then
506 end 448 end
507 end 449 end
508 450
509 local setfenv = setfenv 451 function M.load(ld, source, mode, env)
510 local _load, _loadstring = load, loadstring
511 function load(ld, source, mode, env)
512 mode = mode or "bt" 452 mode = mode or "bt"
513 local chunk, msg 453 local chunk, msg
514 if type( ld ) == "string" then 454 if type( ld ) == "string" then
@@ -516,7 +456,7 @@ if lua_version < "5.3" then
516 local merr = check_mode(mode, ld) 456 local merr = check_mode(mode, ld)
517 if merr then return nil, merr end 457 if merr then return nil, merr end
518 end 458 end
519 chunk, msg = _loadstring(ld, source) 459 chunk, msg = loadstring(ld, source)
520 else 460 else
521 local ld_type = type(ld) 461 local ld_type = type(ld)
522 if ld_type ~= "function" then 462 if ld_type ~= "function" then
@@ -536,10 +476,10 @@ if lua_version < "5.3" then
536 return v 476 return v
537 end 477 end
538 end 478 end
539 chunk, msg = _load(checked_ld, source) 479 chunk, msg = load(checked_ld, source)
540 if merr then return nil, merr end 480 if merr then return nil, merr end
541 else 481 else
542 chunk, msg = _load(ld, source) 482 chunk, msg = load(ld, source)
543 end 483 end
544 end 484 end
545 if not chunk then 485 if not chunk then
@@ -551,11 +491,9 @@ if lua_version < "5.3" then
551 return chunk 491 return chunk
552 end 492 end
553 493
554 loadstring = load 494 M.loadstring = load
555 495
556 local _loadfile = loadfile 496 function M.loadfile(file, mode, env)
557 local io_open = io.open
558 function loadfile(file, mode, env)
559 mode = mode or "bt" 497 mode = mode or "bt"
560 if mode ~= "bt" then 498 if mode ~= "bt" then
561 local f = io_open(file, "rb") 499 local f = io_open(file, "rb")
@@ -568,7 +506,7 @@ if lua_version < "5.3" then
568 end 506 end
569 end 507 end
570 end 508 end
571 local chunk, msg = _loadfile(file) 509 local chunk, msg = loadfile(file)
572 if not chunk then 510 if not chunk then
573 return chunk, msg 511 return chunk, msg
574 end 512 end
@@ -581,7 +519,7 @@ if lua_version < "5.3" then
581 519
582 520
583 if not is_luajit52 then 521 if not is_luajit52 then
584 function rawlen(v) 522 function M.rawlen(v)
585 local t = type(v) 523 local t = type(v)
586 if t ~= "string" and t ~= "table" then 524 if t ~= "string" and t ~= "table" then
587 error("bad argument #1 to 'rawlen' (table or string expected)", 2) 525 error("bad argument #1 to 'rawlen' (table or string expected)", 2)
@@ -591,33 +529,38 @@ if lua_version < "5.3" then
591 end 529 end
592 530
593 531
532 if not is_luajit then
533 function M.xpcall(f, msgh, ...)
534 local args, n = { ... }, select('#', ...)
535 return xpcall(function() return f(unpack(args, 1, n)) end, msgh)
536 end
537 end
538
539
594 if not is_luajit52 then 540 if not is_luajit52 then
595 local os_execute = os.execute 541 function M.os.execute(cmd)
596 function os.execute(cmd)
597 local code = os_execute(cmd) 542 local code = os_execute(cmd)
598 -- Lua 5.1 does not report exit by signal. 543 -- Lua 5.1 does not report exit by signal.
599 if code == 0 then 544 if code == 0 then
600 return true, "exit", code 545 return true, "exit", code
601 else 546 else
602 return nil, "exit", code/256 -- only correct on POSIX! 547 return nil, "exit", code/256 -- only correct on Linux!
603 end 548 end
604 end 549 end
605 end 550 end
606 551
607 552
608 if not table_ok and not is_luajit52 then 553 if not table_ok and not is_luajit52 then
609 table.pack = function(...) 554 M.table.pack = function(...)
610 return { n = select('#', ...), ... } 555 return { n = select('#', ...), ... }
611 end 556 end
612 end 557 end
613 558
614 559
615 local main_coroutine = coroutine.create(function() end) 560 local main_coroutine = coroutine_create(function() end)
616 561
617 local _pcall = pcall 562 function M.coroutine.create(func)
618 local coroutine_create = coroutine.create 563 local success, result = pcall(coroutine_create, func)
619 function coroutine.create(func)
620 local success, result = _pcall(coroutine_create, func)
621 if not success then 564 if not success then
622 if type(func) ~= "function" then 565 if type(func) ~= "function" then
623 error("bad argument #1 (function expected)", 0) 566 error("bad argument #1 (function expected)", 0)
@@ -627,23 +570,18 @@ if lua_version < "5.3" then
627 return result 570 return result
628 end 571 end
629 572
630 -- maps the internal pcall coroutines to the user coroutine that
631 -- *should* be running if pcall didn't use coroutines internally
632 local pcall_mainOf = setmetatable({}, weak_meta)
633
634 if not is_luajit52 then 573 if not is_luajit52 then
635 function coroutine.running() 574 function M.coroutine.running()
636 local co = coroutine_running() 575 local co = coroutine_running()
637 if co then 576 if co then
638 return pcall_mainOf[co] or co, false 577 return co, false
639 else 578 else
640 return main_coroutine, true 579 return main_coroutine, true
641 end 580 end
642 end 581 end
643 end 582 end
644 583
645 local coroutine_yield = coroutine.yield 584 function M.coroutine.yield(...)
646 function coroutine.yield(...)
647 local co, flag = coroutine_running() 585 local co, flag = coroutine_running()
648 if co and not flag then 586 if co and not flag then
649 return coroutine_yield(...) 587 return coroutine_yield(...)
@@ -653,8 +591,7 @@ if lua_version < "5.3" then
653 end 591 end
654 592
655 if not is_luajit then 593 if not is_luajit then
656 local coroutine_resume = coroutine.resume 594 function M.coroutine.resume(co, ...)
657 function coroutine.resume(co, ...)
658 if co == main_coroutine then 595 if co == main_coroutine then
659 return false, "cannot resume non-suspended coroutine" 596 return false, "cannot resume non-suspended coroutine"
660 else 597 else
@@ -662,8 +599,7 @@ if lua_version < "5.3" then
662 end 599 end
663 end 600 end
664 601
665 local coroutine_status = coroutine.status 602 function M.coroutine.status(co)
666 function coroutine.status(co)
667 local notmain = coroutine_running() 603 local notmain = coroutine_running()
668 if co == main_coroutine then 604 if co == main_coroutine then
669 return notmain and "normal" or "running" 605 return notmain and "normal" or "running"
@@ -671,73 +607,11 @@ if lua_version < "5.3" then
671 return coroutine_status(co) 607 return coroutine_status(co)
672 end 608 end
673 end 609 end
674
675 local function pcall_results(current, call, success, ...)
676 if coroutine_status(call) == "suspended" then
677 return pcall_results(current, call, coroutine_resume(call, coroutine_yield(...)))
678 end
679 if pcall_previous then
680 pcall_previous[call] = nil
681 local main = pcall_mainOf[call]
682 if main == current then current = nil end
683 pcall_callOf[main] = current
684 end
685 pcall_mainOf[call] = nil
686 return success, ...
687 end
688 local function pcall_exec(current, call, ...)
689 local main = pcall_mainOf[current] or current
690 pcall_mainOf[call] = main
691 if pcall_previous then
692 pcall_previous[call] = current
693 pcall_callOf[main] = call
694 end
695 return pcall_results(current, call, coroutine_resume(call, ...))
696 end
697 local coroutine_create52 = coroutine.create
698 local function pcall_coroutine(func)
699 if type(func) ~= "function" then
700 local callable = func
701 func = function (...) return callable(...) end
702 end
703 return coroutine_create52(func)
704 end
705 function pcall(func, ...)
706 local current = coroutine_running()
707 if not current then return _pcall(func, ...) end
708 return pcall_exec(current, pcall_coroutine(func), ...)
709 end
710
711 local _tostring = tostring
712 local function xpcall_catch(current, call, msgh, success, ...)
713 if not success then
714 xpcall_running[current] = call
715 local ok, result = _pcall(msgh, ...)
716 xpcall_running[current] = nil
717 if not ok then
718 return false, "error in error handling (".._tostring(result)..")"
719 end
720 return false, result
721 end
722 return true, ...
723 end
724 local _xpcall = xpcall
725 local _unpack = unpack
726 function xpcall(f, msgh, ...)
727 local current = coroutine_running()
728 if not current then
729 local args, n = { ... }, select('#', ...)
730 return _xpcall(function() return f(_unpack(args, 1, n)) end, msgh)
731 end
732 local call = pcall_coroutine(f)
733 return xpcall_catch(current, call, msgh, pcall_exec(current, call, ...))
734 end
735 end -- not luajit 610 end -- not luajit
736 611
737 612
738 if not is_luajit then 613 if not is_luajit then
739 local math_log = math.log 614 M.math.log = function(x, base)
740 math.log = function(x, base)
741 if base ~= nil then 615 if base ~= nil then
742 return math_log(x)/math_log(base) 616 return math_log(x)/math_log(base)
743 else 617 else
@@ -747,11 +621,8 @@ if lua_version < "5.3" then
747 end 621 end
748 622
749 623
750 local package = package
751 if not is_luajit then 624 if not is_luajit then
752 local io_open = io.open 625 function M.package.searchpath(name, path, sep, rep)
753 local table_concat = table.concat
754 function package.searchpath(name, path, sep, rep)
755 sep = (sep or "."):gsub("(%p)", "%%%1") 626 sep = (sep or "."):gsub("(%p)", "%%%1")
756 rep = (rep or package.config:sub(1, 1)):gsub("(%%)", "%%%1") 627 rep = (rep or package.config:sub(1, 1)):gsub("(%%)", "%%%1")
757 local pname = name:gsub(sep, rep):gsub("(%%)", "%%%1") 628 local pname = name:gsub(sep, rep):gsub("(%%)", "%%%1")
@@ -769,48 +640,29 @@ if lua_version < "5.3" then
769 end 640 end
770 end 641 end
771 642
772 local p_index = { searchers = package.loaders }
773 local rawset = rawset
774 setmetatable(package, {
775 __index = p_index,
776 __newindex = function(p, k, v)
777 if k == "searchers" then
778 rawset(p, "loaders", v)
779 p_index.searchers = v
780 else
781 rawset(p, k, v)
782 end
783 end
784 })
785
786 643
787 local string_gsub = string.gsub
788 local function fix_pattern(pattern) 644 local function fix_pattern(pattern)
789 return (string_gsub(pattern, "%z", "%%z")) 645 return (string_gsub(pattern, "%z", "%%z"))
790 end 646 end
791 647
792 local string_find = string.find 648 function M.string.find(s, pattern, ...)
793 function string.find(s, pattern, ...)
794 return string_find(s, fix_pattern(pattern), ...) 649 return string_find(s, fix_pattern(pattern), ...)
795 end 650 end
796 651
797 local string_gmatch = string.gmatch 652 function M.string.gmatch(s, pattern)
798 function string.gmatch(s, pattern)
799 return string_gmatch(s, fix_pattern(pattern)) 653 return string_gmatch(s, fix_pattern(pattern))
800 end 654 end
801 655
802 function string.gsub(s, pattern, ...) 656 function M.string.gsub(s, pattern, ...)
803 return string_gsub(s, fix_pattern(pattern), ...) 657 return string_gsub(s, fix_pattern(pattern), ...)
804 end 658 end
805 659
806 local string_match = string.match 660 function M.string.match(s, pattern, ...)
807 function string.match(s, pattern, ...)
808 return string_match(s, fix_pattern(pattern), ...) 661 return string_match(s, fix_pattern(pattern), ...)
809 end 662 end
810 663
811 if not is_luajit then 664 if not is_luajit then
812 local string_rep = string.rep 665 function M.string.rep(s, n, sep)
813 function string.rep(s, n, sep)
814 if sep ~= nil and sep ~= "" and n >= 2 then 666 if sep ~= nil and sep ~= "" and n >= 2 then
815 return s .. string_rep(sep..s, n-1) 667 return s .. string_rep(sep..s, n-1)
816 else 668 else
@@ -820,7 +672,6 @@ if lua_version < "5.3" then
820 end 672 end
821 673
822 if not is_luajit then 674 if not is_luajit then
823 local string_format = string.format
824 do 675 do
825 local addqt = { 676 local addqt = {
826 ["\n"] = "\\\n", 677 ["\n"] = "\\\n",
@@ -832,15 +683,14 @@ if lua_version < "5.3" then
832 return addqt[c] or string_format("\\%03d", c:byte()) 683 return addqt[c] or string_format("\\%03d", c:byte())
833 end 684 end
834 685
835 local _unpack = unpack 686 function M.string.format(fmt, ...)
836 function string.format(fmt, ...)
837 local args, n = { ... }, select('#', ...) 687 local args, n = { ... }, select('#', ...)
838 local i = 0 688 local i = 0
839 local function adjust_fmt(lead, mods, kind) 689 local function adjust_fmt(lead, mods, kind)
840 if #lead % 2 == 0 then 690 if #lead % 2 == 0 then
841 i = i + 1 691 i = i + 1
842 if kind == "s" then 692 if kind == "s" then
843 args[i] = tostring(args[i]) 693 args[i] = _G.tostring(args[i])
844 elseif kind == "q" then 694 elseif kind == "q" then
845 args[i] = '"'..string_gsub(args[i], "[%z%c\\\"\n]", addquoted)..'"' 695 args[i] = '"'..string_gsub(args[i], "[%z%c\\\"\n]", addquoted)..'"'
846 return lead.."%"..mods.."s" 696 return lead.."%"..mods.."s"
@@ -848,16 +698,13 @@ if lua_version < "5.3" then
848 end 698 end
849 end 699 end
850 fmt = string_gsub(fmt, "(%%*)%%([%d%.%-%+%# ]*)(%a)", adjust_fmt) 700 fmt = string_gsub(fmt, "(%%*)%%([%d%.%-%+%# ]*)(%a)", adjust_fmt)
851 return string_format(fmt, _unpack(args, 1, n)) 701 return string_format(fmt, unpack(args, 1, n))
852 end 702 end
853 end 703 end
854 end 704 end
855 705
856 706
857 local io_open = io.open 707 function M.io.write(...)
858 local io_write = io.write
859 local io_output = io.output
860 function io.write(...)
861 local res, msg, errno = io_write(...) 708 local res, msg, errno = io_write(...)
862 if res then 709 if res then
863 return io_output() 710 return io_output()
@@ -867,28 +714,23 @@ if lua_version < "5.3" then
867 end 714 end
868 715
869 if not is_luajit then 716 if not is_luajit then
870 local lines_iterator 717 local function helper(st, var_1, ...)
871 do 718 if var_1 == nil then
872 local function helper( st, var_1, ... ) 719 if st.doclose then st.f:close() end
873 if var_1 == nil then 720 if (...) ~= nil then
874 if st.doclose then st.f:close() end 721 error((...), 2)
875 if (...) ~= nil then
876 error((...), 2)
877 end
878 end 722 end
879 return var_1, ...
880 end 723 end
724 return var_1, ...
725 end
881 726
882 local _unpack = unpack 727 local function lines_iterator(st)
883 function lines_iterator(st) 728 return helper(st, st.f:read(unpack(st, 1, st.n)))
884 return helper(st, st.f:read(_unpack(st, 1, st.n)))
885 end
886 end 729 end
887 730
888 local valid_format = { ["*l"] = true, ["*n"] = true, ["*a"] = true } 731 local valid_format = { ["*l"] = true, ["*n"] = true, ["*a"] = true }
889 732
890 local io_input = io.input 733 function M.io.lines(fname, ...)
891 function io.lines(fname, ...)
892 local doclose, file, msg 734 local doclose, file, msg
893 if fname ~= nil then 735 if fname ~= nil then
894 doclose, file, msg = true, io_open(fname, "r") 736 doclose, file, msg = true, io_open(fname, "r")
@@ -904,41 +746,17 @@ if lua_version < "5.3" then
904 end 746 end
905 return lines_iterator, st 747 return lines_iterator, st
906 end 748 end
907
908 do
909 local io_stdout = io.stdout
910 local io_type = io.type
911 local file_meta = gmt(io_stdout)
912 if type(file_meta) == "table" and type(file_meta.__index) == "table" then
913 local file_write = file_meta.__index.write
914 file_meta.__index.write = function(self, ...)
915 local res, msg, errno = file_write(self, ...)
916 if res then
917 return self
918 else
919 return nil, msg, errno
920 end
921 end
922
923 file_meta.__index.lines = function(self, ...)
924 if io_type(self) == "closed file" then
925 error("attempt to use a closed file", 2)
926 end
927 local st = { f=self, doclose=false, n=select('#', ...), ... }
928 for i = 1, st.n do
929 if type(st[i]) ~= "number" and not valid_format[st[i]] then
930 error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2)
931 end
932 end
933 return lines_iterator, st
934 end
935 end
936 end
937 end -- not luajit 749 end -- not luajit
938 750
939
940 end -- lua 5.1 751 end -- lua 5.1
941 752
753 -- further write should be forwarded to _G
754 M_meta.__newindex = _G
755
942end -- lua < 5.3 756end -- lua < 5.3
943 757
758
759-- return module table
760return M
761
944-- vi: set expandtab softtabstop=3 shiftwidth=3 : 762-- vi: set expandtab softtabstop=3 shiftwidth=3 :
diff --git a/tests/test.lua b/tests/test.lua
index 83e174e..856230b 100755
--- a/tests/test.lua
+++ b/tests/test.lua
@@ -36,14 +36,26 @@ end
36local V = _VERSION:gsub("^.*(%d+)%.(%d+)$", "%1%2") 36local V = _VERSION:gsub("^.*(%d+)%.(%d+)$", "%1%2")
37if jit then V = "jit" end 37if jit then V = "jit" end
38 38
39print( "testing Lua API ..." ) 39local mode = "global"
40package.path = "../?.lua;"..package.path 40if arg[1] == "module" then
41 mode = "module"
42end
43
44
45package.path = "../?.lua;../?/init.lua;"..package.path
41package.cpath = "./?-"..V..".so;./?-"..V..".dll;./?.so;./?.dll" 46package.cpath = "./?-"..V..".so;./?-"..V..".dll;./?.so;./?.dll"
42require("compat53") 47if mode == "module" then
48 print( "testing Lua API using `compat53.module` ..." )
49 _ENV = require("compat53.module")
50 if setfenv then setfenv(1, _ENV) end
51else
52 print( "testing Lua API using `compat53` ..." )
53 require("compat53")
54end
43 55
44___'' 56___''
45do 57do
46 local t = setmetatable( {}, { __index = { 1, false, "three" } } ) 58 local t = setmetatable({}, { __index = { 1, false, "three" } })
47 for i,v in ipairs(t) do 59 for i,v in ipairs(t) do
48 print("ipairs", i, v) 60 print("ipairs", i, v)
49 end 61 end
@@ -338,22 +350,24 @@ do
338 print("xpcall()", xpcall(func, debug.traceback, false)) 350 print("xpcall()", xpcall(func, debug.traceback, false))
339 print("xpcall()", xpcall(func, debug.traceback, true)) 351 print("xpcall()", xpcall(func, debug.traceback, true))
340 print("xpcall()", xpcall(func, tb, true)) 352 print("xpcall()", xpcall(func, tb, true))
341 local function func2(cb) 353 if mode ~= "module" then
342 print("xpcall()", xpcall(cb, debug.traceback, "str")) 354 local function func2(cb)
343 end 355 print("xpcall()", xpcall(cb, debug.traceback, "str"))
344 local function func3(cb) 356 end
345 print("pcall()", pcall(cb, "str")) 357 local function func3(cb)
358 print("pcall()", pcall(cb, "str"))
359 end
360 local function cb(arg)
361 coroutine.yield(2)
362 return arg
363 end
364 local c = coroutine.wrap(func2)
365 print("xpcall()", c(cb))
366 print("xpcall()", c())
367 local c = coroutine.wrap(func3)
368 print("pcall()", c(cb))
369 print("pcall()", c())
346 end 370 end
347 local function cb(arg)
348 coroutine.yield(2)
349 return arg
350 end
351 local c = coroutine.wrap(func2)
352 print("xpcall()", c(cb))
353 print("xpcall()", c())
354 local c = coroutine.wrap(func3)
355 print("pcall()", c(cb))
356 print("pcall()", c())
357end 371end
358 372
359 373
@@ -387,9 +401,11 @@ do
387 print("coroutine.running()", F(coroutine.running())) 401 print("coroutine.running()", F(coroutine.running()))
388 local main_co, co1, co2 = coroutine.running() 402 local main_co, co1, co2 = coroutine.running()
389 -- coroutine.yield 403 -- coroutine.yield
390 print("coroutine.yield()", pcall(function() 404 if mode ~= "module" then
391 coroutine.yield(1, 2, 3) 405 print("coroutine.yield()", pcall(function()
392 end)) 406 coroutine.yield(1, 2, 3)
407 end))
408 end
393 print("coroutine.yield()", coroutine.wrap(function() 409 print("coroutine.yield()", coroutine.wrap(function()
394 coroutine.yield(1, 2, 3) 410 coroutine.yield(1, 2, 3)
395 end)()) 411 end)())
@@ -428,13 +444,13 @@ do
428 local path, prefix = "./?.lua;?/init.lua;../?.lua", "package.searchpath()" 444 local path, prefix = "./?.lua;?/init.lua;../?.lua", "package.searchpath()"
429 print(prefix, package.searchpath("no.such.module", path)) 445 print(prefix, package.searchpath("no.such.module", path))
430 print(prefix, package.searchpath("no.such.module", "")) 446 print(prefix, package.searchpath("no.such.module", ""))
431 print(prefix, package.searchpath("compat52", path)) 447 print(prefix, package.searchpath("compat53", path))
432 print(prefix, package.searchpath("no:such:module", path, ":", "|")) 448 print(prefix, package.searchpath("no:such:module", path, ":", "|"))
433end 449end
434 450
435 451
436___'' 452___''
437do 453if mode ~= "module" then
438 local function mod_func() return {} end 454 local function mod_func() return {} end
439 local function my_searcher(name) 455 local function my_searcher(name)
440 if name == "my.module" then 456 if name == "my.module" then
@@ -462,19 +478,19 @@ end
462 478
463___'' 479___''
464do 480do
465 print("string.find()", ("abc\0abc\0abc"):find("[^a\0]+")) 481 print("string.find()", string.find("abc\0abc\0abc", "[^a\0]+"))
466 print("string.find()", ("abc\0abc\0abc"):find("%w+\0", 5)) 482 print("string.find()", string.find("abc\0abc\0abc", "%w+\0", 5))
467 for x in ("abc\0def\0ghi"):gmatch("[^\0]+") do 483 for x in string.gmatch("abc\0def\0ghi", "[^\0]+") do
468 print("string.gmatch()", x) 484 print("string.gmatch()", x)
469 end 485 end
470 for x in ("abc\0def\0ghi"):gmatch("%w*\0") do 486 for x in string.gmatch("abc\0def\0ghi", "%w*\0") do
471 print("string.gmatch()", #x) 487 print("string.gmatch()", #x)
472 end 488 end
473 print("string.gsub()", ("abc\0def\0ghi"):gsub("[\0]", "X")) 489 print("string.gsub()", string.gsub("abc\0def\0ghi", "[\0]", "X"))
474 print("string.gsub()", ("abc\0def\0ghi"):gsub("%w*\0", "X")) 490 print("string.gsub()", string.gsub("abc\0def\0ghi", "%w*\0", "X"))
475 print("string.gsub()", ("abc\0def\0ghi"):gsub("%A", "X")) 491 print("string.gsub()", string.gsub("abc\0def\0ghi", "%A", "X"))
476 print("string.match()", ("abc\0abc\0abc"):match("([^\0a]+)")) 492 print("string.match()", string.match("abc\0abc\0abc", "([^\0a]+)"))
477 print("string.match()", #("abc\0abc\0abc"):match(".*\0")) 493 print("string.match()", #string.match("abc\0abc\0abc", ".*\0"))
478 print("string.rep()", string.rep("a", 0)) 494 print("string.rep()", string.rep("a", 0))
479 print("string.rep()", string.rep("b", 1)) 495 print("string.rep()", string.rep("b", 1))
480 print("string.rep()", string.rep("c", 4)) 496 print("string.rep()", string.rep("c", 4))
@@ -533,30 +549,32 @@ do
533 print("io.lines()", pcall(function() 549 print("io.lines()", pcall(function()
534 for l in io.lines("no_such_file.txt") do print(l) end 550 for l in io.lines("no_such_file.txt") do print(l) end
535 end)) 551 end))
536 local f = assert(io.open("test.lua", "r")) 552 if mode ~= "module" then
537 for a,b in f:lines(2, "*l") do 553 local f = assert(io.open("test.lua", "r"))
538 print("file:lines()", a, b) 554 for a,b in f:lines(2, "*l") do
539 break 555 print("file:lines()", a, b)
556 break
557 end
558 f:close()
559 f = assert(io.open("data.txt", "r"))
560 for n1,n2,rest in f:lines("*n", "*n", "*a") do
561 print("file:lines()", n1, n2, rest)
562 end
563 f:close()
564 f = assert(io.open("data.txt", "r"))
565 for l in f:lines() do
566 print("file:lines()", l)
567 end
568 f:close()
569 print("file:lines()", pcall(function()
570 for l in f:lines() do print(l) end
571 end))
572 print("file:lines()", pcall(function()
573 local f = assert(io.open("data.txt", "r"))
574 for l in f:lines("*l", "*x") do print(l) end
575 f:close()
576 end))
540 end 577 end
541 f:close()
542 f = assert(io.open("data.txt", "r"))
543 for n1,n2,rest in f:lines("*n", "*n", "*a") do
544 print("file:lines()", n1, n2, rest)
545 end
546 f:close()
547 f = assert(io.open("data.txt", "r"))
548 for l in f:lines() do
549 print("file:lines()", l)
550 end
551 f:close()
552 print("file:lines()", pcall(function()
553 for l in f:lines() do print(l) end
554 end))
555 print("file:lines()", pcall(function()
556 local f = assert(io.open("data.txt", "r"))
557 for l in f:lines("*l", "*x") do print(l) end
558 f:close()
559 end))
560 os.remove("data.txt") 578 os.remove("data.txt")
561end 579end
562___'' 580___''