diff options
| author | Philipp Janda <siffiejoe@gmx.net> | 2015-04-29 12:26:34 +0200 |
|---|---|---|
| committer | Philipp Janda <siffiejoe@gmx.net> | 2015-04-29 12:26:34 +0200 |
| commit | c87038c1f3a6d3a21d14d6db1affbf879a25386a (patch) | |
| tree | 0bbdb4925e1c47185b32f5e678a1265b80e69862 | |
| parent | ec5331cb94f9100fe4cf26d1ea215dd66e8e185c (diff) | |
| parent | 17fdace5c04486db3470fe7022aee7eac8efc3af (diff) | |
| download | lua-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.md | 18 | ||||
| -rw-r--r-- | compat53/init.lua | 324 | ||||
| -rw-r--r-- | compat53/module.lua (renamed from compat53.lua) | 470 | ||||
| -rwxr-xr-x | tests/test.lua | 130 |
4 files changed, 559 insertions, 383 deletions
| @@ -42,6 +42,22 @@ string packing modules automatically. If unsuccessful, pure Lua | |||
| 42 | versions of the new `table` functions are used as a fallback, and | 42 | versions 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 | ||
| 48 | local _ENV = require("compat53.module") | ||
| 49 | if setfenv then setfenv(1, _ENV) end | ||
| 50 | ``` | ||
| 51 | |||
| 52 | The `compat53.module` module does not modify the global environment, | ||
| 53 | and so it is safe to use in modules without affecting other Lua files. | ||
| 54 | It is supposed to be set as the current environment (see above), i.e. | ||
| 55 | cherry picking individual functions from this module is expressly | ||
| 56 | *not* supported!). Not all features are available when using this | ||
| 57 | module (e.g. yieldable (x)pcall support, string/file methods, etc.), | ||
| 58 | so it is recommended to use plain `require("compat53")` whenever | ||
| 59 | possible. | ||
| 60 | |||
| 45 | ### C code | 61 | ### C code |
| 46 | 62 | ||
| 47 | There are two ways of adding the C API compatibility functions/macros to | 63 | There 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 @@ | |||
| 1 | local _G, _VERSION, type, pairs, require = | ||
| 2 | _G, _VERSION, type, pairs, require | ||
| 3 | |||
| 4 | local M = require("compat53.module") | ||
| 5 | local lua_version = _VERSION:sub(-3) | ||
| 6 | |||
| 7 | |||
| 8 | -- apply other global effects | ||
| 9 | if 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 | |||
| 304 | end -- lua == 5.1 | ||
| 305 | |||
| 306 | |||
| 307 | -- handle exporting to global scope | ||
| 308 | local 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 | ||
| 320 | end | ||
| 321 | |||
| 322 | extend_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 @@ | |||
| 1 | local _G, _VERSION = _G, _VERSION | ||
| 1 | local lua_version = _VERSION:sub(-3) | 2 | local lua_version = _VERSION:sub(-3) |
| 2 | 3 | ||
| 4 | |||
| 5 | local M = _G | ||
| 6 | |||
| 3 | if lua_version < "5.3" then | 7 | if 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 | |||
| 942 | end -- lua < 5.3 | 756 | end -- lua < 5.3 |
| 943 | 757 | ||
| 758 | |||
| 759 | -- return module table | ||
| 760 | return 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 | |||
| 36 | local V = _VERSION:gsub("^.*(%d+)%.(%d+)$", "%1%2") | 36 | local V = _VERSION:gsub("^.*(%d+)%.(%d+)$", "%1%2") |
| 37 | if jit then V = "jit" end | 37 | if jit then V = "jit" end |
| 38 | 38 | ||
| 39 | print( "testing Lua API ..." ) | 39 | local mode = "global" |
| 40 | package.path = "../?.lua;"..package.path | 40 | if arg[1] == "module" then |
| 41 | mode = "module" | ||
| 42 | end | ||
| 43 | |||
| 44 | |||
| 45 | package.path = "../?.lua;../?/init.lua;"..package.path | ||
| 41 | package.cpath = "./?-"..V..".so;./?-"..V..".dll;./?.so;./?.dll" | 46 | package.cpath = "./?-"..V..".so;./?-"..V..".dll;./?.so;./?.dll" |
| 42 | require("compat53") | 47 | if mode == "module" then |
| 48 | print( "testing Lua API using `compat53.module` ..." ) | ||
| 49 | _ENV = require("compat53.module") | ||
| 50 | if setfenv then setfenv(1, _ENV) end | ||
| 51 | else | ||
| 52 | print( "testing Lua API using `compat53` ..." ) | ||
| 53 | require("compat53") | ||
| 54 | end | ||
| 43 | 55 | ||
| 44 | ___'' | 56 | ___'' |
| 45 | do | 57 | do |
| 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()) | ||
| 357 | end | 371 | end |
| 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, ":", "|")) |
| 433 | end | 449 | end |
| 434 | 450 | ||
| 435 | 451 | ||
| 436 | ___'' | 452 | ___'' |
| 437 | do | 453 | if 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 | ___'' |
| 464 | do | 480 | do |
| 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") |
| 561 | end | 579 | end |
| 562 | ___'' | 580 | ___'' |
